diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 691b237d..a01ec8fa 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -3,7 +3,7 @@ name: Linux on: [push, pull_request] jobs: - gcc7: + gcc10: strategy: fail-fast: false matrix: @@ -19,7 +19,7 @@ jobs: - name: Install Dependencies run: | sudo apt-get update - sudo apt-get install -yq libgtest-dev libboost-program-options-dev rapidjson-dev ninja-build + sudo apt-get install -yq libgtest-dev libboost-program-options-dev rapidjson-dev ninja-build gcc-10 g++-10 - name: Build GTest run: | @@ -34,6 +34,9 @@ jobs: - name: Configure CMake shell: pwsh + env: + CC: gcc-10 + CXX: g++-10 working-directory: build/ run: | $cmakeBuildType = '${{ matrix.config }}' diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 91ddd7fb..fe33c88f 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -9,7 +9,7 @@ jobs: matrix: config: [Debug, Release] - runs-on: macos-latest + runs-on: macos-11 steps: - uses: actions/checkout@v2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a24b3b6..83c6e626 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,10 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -cmake_minimum_required(VERSION 3.8.2) +cmake_minimum_required(VERSION 3.15) -if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.15") - # Enable CMAKE_MSVC_RUNTIME_LIBRARY on Windows. - set(MSVC_MATCH_VCPKG_TRIPLET ON) - cmake_policy(SET CMP0091 NEW) -endif() +# Enable CMAKE_MSVC_RUNTIME_LIBRARY on Windows: https://cmake.org/cmake/help/latest/policy/CMP0091.html +cmake_policy(SET CMP0091 NEW) # Default to the last updated version from version.txt. file(TO_CMAKE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.txt" VERSION_FILE) @@ -33,8 +30,6 @@ endif() project(cppgraphqlgen VERSION ${LATEST_VERSION}) -set(CMAKE_CXX_STANDARD 17) - set(GRAPHQL_INSTALL_INCLUDE_DIR include CACHE PATH "Header file install directory") set(GRAPHQL_INSTALL_TOOLS_DIR bin CACHE PATH "schemagen install directory") set(GRAPHQL_INSTALL_CMAKE_DIR lib/cmake CACHE PATH "CMake config files install directory") @@ -45,7 +40,7 @@ option(BUILD_SHARED_LIBS "Build shared libraries instead of static libs" OFF) if(VCPKG_TARGET_TRIPLET) message(STATUS "Using ${VCPKG_TARGET_TRIPLET} triplet with vcpkg") - if(MSVC AND MSVC_MATCH_VCPKG_TRIPLET) + if(MSVC) # Match the MSVC runtime if we're using VCPKG with static libraries. if(VCPKG_TARGET_TRIPLET MATCHES [[^.+-static$]]) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") diff --git a/PEGTL b/PEGTL index 7d039707..1643777c 160000 --- a/PEGTL +++ b/PEGTL @@ -1 +1 @@ -Subproject commit 7d039707cf835cea63daa78a717e18fcc5bcf95b +Subproject commit 1643777c2d8cfe01668e217aa7d4cbd6b9f173ba diff --git a/README.md b/README.md index d0e95987..5f8e6fce 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,7 @@ service, you can use the same GraphQL client code to access your native data sou service online. You might even be able to share some more of that code between a progressive web app and your native/hybrid app. -If what you're after is a way to consume a GraphQL service from C++, as of -[v3.6.0](https://github.com/microsoft/cppgraphqlgen/releases/tag/v3.6.0) this project also includes +If what you're after is a way to consume a GraphQL service from C++, this project also includes a `graphqlclient` library and a `clientgen` utility to generate types matching a GraphQL request document, its variables, and all of the serialization code you need to talk to a `graphqlservice` implementation. If you want to consume another service, you will need access to the schema definition @@ -32,53 +31,85 @@ implementation. If you want to consume another service, you will need access to any variables to the service and parse its responses into a `graphql::response::Value` (e.g. with the `graphqljson` library) in your code. -# Getting Started - ## Related projects -I created a couple of sample projects that work with the latest version to demonstrate integrating the -[schema.today.graphql](./samples/schema.today.graphql) service into an Electron app. They're available under -my personal account, feel free to use either or both of these as a starting point to integrate your own generated -service with Node or Electron. PRs with links to your own samples are always welcome. - +The most complete examples I've built are related to [GqlMAPI](https://github.com/microsoft/gqlmapi): +- [eMAPI](https://github.com/microsoft/eMAPI): Windows-only Electron app which lets you access +the [MAPI](https://en.wikipedia.org/wiki/MAPI) interface used by +[Microsoft Outlook](https://en.wikipedia.org/wiki/Microsoft_Outlook). Its goal is to be a spiritual +successor to a debugging and diagnostic tool called +[MFCMAPI](https://github.com/stephenegriffin/mfcmapi). +- [electron-gqlmapi](https://github.com/microsoft/electron-gqlmapi): Native module for Electron +which hosts `GqlMAPI` in `eMAPI`. It includes JS libraries for calling the native module across the +Electron IPC channel. +- [Tauri-GqlMAPI](https://github.com/wravery/tauri-gqlmapi): Reimplementation of `eMAPI` built +in [Rust](https://www.rust-lang.org/) and [TypeScript](https://www.typescriptlang.org/) on top of +[Tauri](https://tauri.studio/en). +- [gqlmapi-rs](https://github.com/wravery/gqlmapi-rs): `Rust` crate I built to expose safe +bindings for `GqlMAPI`. It is loosely based on `electron-gqlmapi`, and it is used by +`Tauri-GqlMAPI`. + +I created a couple of sample projects that worked with earlier versions of `cppgraphqlgen` to +demonstrate integrating the [schema.today.graphql](./samples/schema.today.graphql) service into an +Electron app. They're still available under my personal account, but I haven't updated them +recently: - [electron-cppgraphql](https://github.com/wravery/electron-cppgraphql): Node Native Module which compiles -against the version of the Node headers included in Electron. +against the version of the Node headers included in Electron. This was the starting point for +`electron-gqlmapi`, and it is still useful as a sample because it does not depend on a platform-specific +API like `MAPI`, so it works cross-platform. - [cppgraphiql](https://github.com/wravery/cppgraphiql): Electron app which consumes `electron-cppgraphql` and exposes an instance of [GraphiQL](https://github.com/graphql/graphiql) on top of it. -## Installation process +Feel free to use either or both of these as a starting point to integrate your own generated +service with `Node`, `Electron`, or `Tauri`. PRs with links to your own samples are always welcome. -I've tested this on Windows with both Visual Studio 2017 and 2019, and on Linux using an Ubuntu 20.04 LTS instance running in -WSL with both gcc 9.3.0 and clang 10.0.0. The key compiler requirement is support for C++17 including std::filesystem, earlier -versions of gcc and clang may not have enough support for that. +# Getting Started -The easiest way to get all of these and to build `cppgraphqlgen` in one step is to use -[microsoft/vcpkg](https://github.com/microsoft/vcpkg). To install with vcpkg, make sure you've pulled the latest version -and then run `vcpkg install cppgraphqlgen` (or `cppgraphqlgen:x64-windows`, `cppgraphqlgen:x86-windows-static`, etc. -depending on your platform). To install just the dependencies and work in a clone of this repo, you'll need some subset -of `vcpkg install pegtl boost-program-options rapidjson gtest`. It works for Windows, Linux, and Mac, -but if you want to try building for another platform (e.g. Android or iOS), you'll need to do more of this manually. +## Installation process -Manual installation will work best if you clone the GitHub repos for each of the dependencies and follow the installation -instructions for each project. You might also be able to find pre-built packages depending on your platform, but the -versions need to match. +The minimum OS and toolchain versions I've tested with this version of `cppgraphqlgen` are: +- Microsoft Windows: Visual Studio 2019 +- Linux: Ubuntu 20.04 LTS with gcc 10.3.0 +- macOS: 11 (Big Sur) with AppleClang 13.0.0. + +The key compiler requirement is support for C++20 including coroutines and concepts. Some of these compiler +versions still treat coroutine support as experimental, and the CMake configuration can auto-detect that, +but earlier versions of gcc and clang do not seem to have enough support for C++20. + +The easiest way to build and install `cppgraphqlgen` is to use [microsoft/vcpkg](https://github.com/microsoft/vcpkg). +See the [Getting Started](https://github.com/microsoft/vcpkg#getting-started) section of the `vcpkg` README +for details. Once you have that configured, run `vcpkg install cppgraphqlgen` (or `cppgraphqlgen:x64-windows`, +`cppgraphqlgen:x86-windows-static`, etc. depending on your platform). That will build and install all of the +dependencies for `cppgraphqlgen`, and then build `cppgraphqlgen` itself without any other setup. The `cppgraphqlgen` +package (and its dependencies) are advertised to the `CMake` `find_package` function through the +`-DCMAKE_TOOLCHAIN_FILE=<...>/scripts/buildsystems/vcpkg.cmake` parameter/variable. There are more details about +this in the `vcpkg` documentation. + +If you want to build `cppgraphqlgen` yourself, you can do that with `CMake` from a clone or archive of this repo. +See the [Build and Test](#build-and-test) section below for instructions. You will need to install the dependencies +first where `find_package` can find them. If `vcpkg` works otherwise, you can do that with `vcpkg install pegtl +boost-program-options rapidjson gtest`. Some of these are optional, if for example you do not build the tests. If +`vcpkg` does not work, please see the documentation for each of those dependencies, as well as your +platform/toolchain documentation for perferred installation mechanisms. You may need to build some or all of them +separately from source. ## Software dependencies The build system for this project uses [CMake](http://www.cmake.org/). You will need to have CMake (at least version -3.8.0) installed, and the library dependencies need to be where CMake can find them. Otherwise you need to disable the +3.15.0) installed, and the library dependencies need to be where CMake can find them. Otherwise you need to disable the options which depend on them. -I also picked a few other projects as dependencies, most of which are optional when consuming this project. If you -redistribute any binaries built from these libraries, you should still follow the terms of their individual licenses. As -of this writing, this library and all of its redistributable dependencies are available under the MIT license, which -means you need to include an acknowledgement along with the license text. +Besides the MIT license for this project, if you redistribute any source code or binaries built from these library +dependencies, you should still follow the terms of their individual licenses. As of this writing, this library and +all of its dependencies are available under either the MIT License or the Boost Software License (BSL). Both +licenses roughly mean that you may redistribute them freely as long as you include an acknowledgement along with +the license text. Please see the license or copyright notice which comes with each project for more details. ### graphqlpeg -- GraphQL parsing: [Parsing Expression Grammar Template Library (PEGTL)](https://github.com/taocpp/PEGTL) release 3.2.0, +- GraphQL parsing: [Parsing Expression Grammar Template Library (PEGTL)](https://github.com/taocpp/PEGTL) release 3.2.2, which is part of [The Art of C++](https://taocpp.github.io/) library collection. I've added this as a sub-module, so you -do not need to install this separately. If you already have 3.2.0 installed where CMake can find it, it will use that +do not need to install this separately. If you already have 3.2.2 installed where CMake can find it, it will use that instead of the sub-module and avoid installing another copy of PEGTL. ### graphqlservice @@ -157,7 +188,7 @@ The generated code depends on the `graphqlclient` library for serialization of b code, you'll also need to link `graphqlclient`, `graphqlpeg` for the pre-parsed, pre-validated request AST, and `graphqlresponse` for the `graphql::response::Value` implementation. -Sample output for `clientgen` is in the [samples/client](samples/client) directory, and each sample is consumed by +Sample output for `clientgen` is in the sub-directories of [samples/client](samples/client), and each sample is consumed by a unit test in [test/ClientTests.cpp](test/ClientTests.cpp). ### tests (`GRAPHQL_BUILD_TESTS=ON`) @@ -169,14 +200,27 @@ configuration. ## API references See [GraphQLService.h](include/graphqlservice/GraphQLService.h) for the base types implemented in -the `graphql::service` namespace. Take a look at [TodayMock.h](samples/today/TodayMock.h) and -[TodayMock.cpp](samples/today/TodayMock.cpp) to see a sample implementation of a custom schema defined -in [schema.today.graphql](samples/schema.today.graphql) for testing purposes. +the `graphql::service` namespace. + +Take a look at the [samples/learn](samples/learn) directory, starting with +[StarWarsData.cpp](samples/learn/StarWarsData.cpp) to see a sample implementation of a custom schema defined in +[schema.learn.graphql](samples/learn/schema/schema.learn.graphql). This is the same schema and sample data used in the +GraphQL tutorial on https://graphql.org/learn/. This directory builds an interactive command line application which +can execute query and mutation operations against the sample data in memory. + +There are several helper functions for `CMake` declared in +[cmake/cppgraphqlgen-functions.cmake](cmake/cppgraphqlgen-functions.cmake), which is automatically included if you use +`find_package(cppgraphqlgen)` in your own `CMake` project. See +[samples/learn/schema/CMakeLists.txt](samples/learn/schema/CMakeLists.txt) and +[samples/learn/CMakeLists.txt](samples/learn/CMakeLists.txt), or the `CMakeLists.txt` files in some of the +other samples sub-directories for examples of how to use them to automatically rerun the code generators and update +the files in your source directory. ### Additional Documentation There are some more targeted documents in the [doc](./doc) directory: +* [Awaitable Types](./doc/awaitable.md) * [Parsing GraphQL](./doc/parsing.md) * [Query Responses](./doc/responses.md) * [JSON Representation](./doc/json.md) @@ -187,14 +231,28 @@ There are some more targeted documents in the [doc](./doc) directory: ### Samples -All of the generated files are in the [samples](samples/) directory. There are two different versions of -the generated code, one which creates a single pair of files (`samples/unified/`), and one which uses the -`--separate-files` flag with `schemagen` to generate individual header and source files (`samples/separate/`) -for each of the object types which need to be implemeneted. The only difference between -[TodayMock.h](samples/today/TodayMock.h) with and without `IMPL_SEPARATE_TODAY` defined should be that the -`--separate-files` option generates a [TodayObjects.h](samples/separate/TodayObjects.h) convenience header -which includes all of the inidividual object header along with the rest of the schema in -[TodaySchema.h](samples/separate/TodaySchema.h). +All of the samples are under [samples](samples/), with nested sub-directories for generated files: +- [samples/today](samples/today/): There are two different samples generated from +[schema.today.graphql](samples/today/schema.today.graphql) in this directory. The default +[schema](samples/today/schema/) target includes Introspection support (which is the default), while the +[nointrospection](samples/today/nointrospection/) target demonstrates how to disable Introspection support +with the `schemagen --no-introspection` parameter. The mock implementation of the service for both schemas is in +[samples/today/TodayMock.h](samples/today/TodayMock.h) and [samples/today/TodayMock.cpp](samples/today/TodayMock.cpp). +It builds an interactive `sample`/`sample_nointrospection` and `benchmark`/`benchmark_nointrospection` target for +each version, and it uses each of them in several unit tests. +- [samples/client](samples/client/): Several sample queries built with `clientgen` against the +[schema.today.graphql](samples/today/schema.today.graphql) schema shared with [samples/today](samples/today/). It +includes a `client_benchmark` executable for comparison with benchmark executables using the same hardcoded query +in [samples/today/]. The benchmark links with the default [schema](samples/today/schema/) target in +[samples/today](samples/today/) to handle the benchmark query. +- [samples/learn](samples/learn/): Simpler standalone which builds a `learn_star_wars` executable that follows +the tutorial examples on https://graphql.org/learn/. +- [samples/validation](samples/validation/): This schema is based on the examples and counter-examples from the +[Validation](https://spec.graphql.org/October2021/#sec-Validation) section of the October 2021 GraphQL spec. There +is no implementation of this schema, it relies entirely generated stubs (created with `schemagen --stubs`) to build +successfully without defining more than placeholder objects fo the Query, Mutation, and Subscription operations in +[samples/validation/ValidationMock.h](samples/validation/ValidationMock.h). It is used to test the validation logic +with every example or counter-example in the spec in [test/ValidationTests.cpp](test/ValidationTests.cpp). # Build and Test @@ -211,7 +269,7 @@ can run all of them from there. Your experience will vary depending on your build toolchain. The same instructions should work for any platform that CMake supports. These basic steps will build and run the tests. You can add options to build in another target directory, -change the config from `Debug` (default) to `Release`, use another build tool like `Ninja`, etc. If you are using vcpkg +change the config from `Debug` (default) to `Release`, use another build tool like `Ninja`, etc. If you are using `vcpkg` to install the dependencies, remember to specify the `-DCMAKE_TOOLCHAIN_FILE=...` option when you run the initial build configuration. @@ -226,8 +284,8 @@ You can then optionally install the public outputs by configuring it with `Relea ## Interactive tests -If you want to try an interactive version, you can run `samples/sample` and paste in queries against -the same mock service or load a query from a file on the command line. +If you want to try an interactive version, you can run `samples/today/sample` or `samples/today/sample_nointrospection` +and paste in queries against the same mock service or load a query from a file on the command line. ## Reporting Security Issues diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index bc212859..1db60cea 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -cmake_minimum_required(VERSION 3.8.2) +cmake_minimum_required(VERSION 3.15) # Enable version checks in find_package include(CMakePackageConfigHelpers) @@ -11,3 +11,10 @@ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake DESTINATION ${GRAPHQL_INSTALL_CMAKE_DIR}/${PROJECT_NAME}) + +install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}-functions.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}-update-schema-files.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}-update-client-files.cmake + CONFIGURATIONS ${GRAPHQL_INSTALL_CONFIGURATIONS} + DESTINATION ${GRAPHQL_INSTALL_CMAKE_DIR}/${PROJECT_NAME}) diff --git a/cmake/cppgraphqlgen-config.cmake b/cmake/cppgraphqlgen-config.cmake index 2adc2fb5..df9b03b6 100644 --- a/cmake/cppgraphqlgen-config.cmake +++ b/cmake/cppgraphqlgen-config.cmake @@ -5,7 +5,7 @@ cppgraphqlgen ------------- -The following import targets are created +The following import targets are created: :: @@ -15,8 +15,20 @@ The following import targets are created cppgraphqlgen::graphqlintrospection cppgraphqlgen::graphqljson cppgraphqlgen::schemagen + cppgraphqlgen::clientgen + +The following functions are defined to help with code generation and build targets: + +:: + + update_graphql_schema_files + add_graphql_schema_target + add_graphql_schema_no_introspection_target + update_graphql_client_files + add_graphql_client_target #]=======================================================================] include(CMakeFindDependencyMacro) find_package(Threads REQUIRED) include("${CMAKE_CURRENT_LIST_DIR}/cppgraphqlgen-targets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/cppgraphqlgen-functions.cmake") diff --git a/cmake/cppgraphqlgen-functions.cmake b/cmake/cppgraphqlgen-functions.cmake new file mode 100644 index 00000000..91fa3404 --- /dev/null +++ b/cmake/cppgraphqlgen-functions.cmake @@ -0,0 +1,107 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +get_filename_component(GRAPHQL_UPDATE_SCHEMA_FILES_SCRIPT + "${CMAKE_CURRENT_LIST_DIR}/cppgraphqlgen-update-schema-files.cmake" + ABSOLUTE) + +get_filename_component(GRAPHQL_UPDATE_CLIENT_FILES_SCRIPT + "${CMAKE_CURRENT_LIST_DIR}/cppgraphqlgen-update-client-files.cmake" + ABSOLUTE) + +function(update_graphql_schema_files SCHEMA_TARGET SCHEMA_GRAPHQL SCHEMA_PREFIX SCHEMA_NAMESPACE) + set_property(DIRECTORY APPEND + PROPERTY CMAKE_CONFIGURE_DEPENDS ${SCHEMA_TARGET}_schema_files) + + # Collect optional arguments + set(ADDITIONAL_SCHEMAGEN_ARGS "") + if(ARGC GREATER 4) + math(EXPR LAST_ARG "${ARGC} - 1") + foreach(ARGN RANGE 4 ${LAST_ARG}) + set(NEXT_ARG "${ARGV${ARGN}}") + list(APPEND ADDITIONAL_SCHEMAGEN_ARGS "${NEXT_ARG}") + endforeach() + endif() + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_TARGET}_schema_files + COMMAND + ${CMAKE_COMMAND} "-DSCHEMA_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}" + "-DSCHEMA_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}" + "-DSCHEMAGEN_PROGRAM=$" + "-DSCHEMA_TARGET=${SCHEMA_TARGET}" "-DSCHEMA_GRAPHQL=${SCHEMA_GRAPHQL}" + "-DSCHEMA_PREFIX=${SCHEMA_PREFIX}" "-DSCHEMA_NAMESPACE=${SCHEMA_NAMESPACE}" + "-DADDITIONAL_SCHEMAGEN_ARGS=${ADDITIONAL_SCHEMAGEN_ARGS}" + -P ${GRAPHQL_UPDATE_SCHEMA_FILES_SCRIPT} + DEPENDS ${SCHEMA_GRAPHQL} ${GRAPHQL_UPDATE_SCHEMA_FILES_SCRIPT} cppgraphqlgen::schemagen + COMMENT "Generating ${SCHEMA_TARGET} GraphQL schema" + VERBATIM) +endfunction() + +function(add_graphql_schema_target SCHEMA_TARGET) + add_custom_target(${SCHEMA_TARGET}_update_schema ALL + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_TARGET}_schema_files) + + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_TARGET}_schema_files) + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_TARGET}_schema_files SCHEMA_FILES) + add_library(${SCHEMA_TARGET}_schema STATIC ${SCHEMA_FILES}) + add_dependencies(${SCHEMA_TARGET}_schema ${SCHEMA_TARGET}_update_schema) + target_include_directories(${SCHEMA_TARGET}_schema PUBLIC $) + target_link_libraries(${SCHEMA_TARGET}_schema PUBLIC cppgraphqlgen::graphqlintrospection) + endif() +endfunction() + +function(add_graphql_schema_no_introspection_target SCHEMA_NO_INTROSPECTION_TARGET) + add_custom_target(${SCHEMA_NO_INTROSPECTION_TARGET}_update_schema ALL + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_NO_INTROSPECTION_TARGET}_schema_files) + + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_NO_INTROSPECTION_TARGET}_schema_files) + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/${SCHEMA_NO_INTROSPECTION_TARGET}_schema_files SCHEMA_FILES) + add_library(${SCHEMA_NO_INTROSPECTION_TARGET}_schema STATIC ${SCHEMA_FILES}) + add_dependencies(${SCHEMA_NO_INTROSPECTION_TARGET}_schema ${SCHEMA_NO_INTROSPECTION_TARGET}_update_schema) + target_include_directories(${SCHEMA_NO_INTROSPECTION_TARGET}_schema PUBLIC $) + target_link_libraries(${SCHEMA_NO_INTROSPECTION_TARGET}_schema PUBLIC cppgraphqlgen::graphqlservice) + endif() +endfunction() + +function(update_graphql_client_files CLIENT_TARGET SCHEMA_GRAPHQL REQUEST_GRAPHQL CLIENT_PREFIX CLIENT_NAMESPACE) + set_property(DIRECTORY APPEND + PROPERTY CMAKE_CONFIGURE_DEPENDS ${CLIENT_TARGET}_client_files) + + # Collect optional arguments + set(ADDITIONAL_CLIENTGEN_ARGS "") + if(ARGC GREATER 5) + math(EXPR LAST_ARG "${ARGC} - 1") + foreach(ARGN RANGE 5 ${LAST_ARG}) + set(NEXT_ARG "${ARGV${ARGN}}") + list(APPEND ADDITIONAL_CLIENTGEN_ARGS "${NEXT_ARG}") + endforeach() + endif() + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${CLIENT_TARGET}_client_files + COMMAND + ${CMAKE_COMMAND} "-DCLIENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}" + "-DCLIENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}" + "-DCLIENTGEN_PROGRAM=$" "-DCLIENT_TARGET=${CLIENT_TARGET}" + "-DSCHEMA_GRAPHQL=${SCHEMA_GRAPHQL}" "-DREQUEST_GRAPHQL=${REQUEST_GRAPHQL}" + "-DCLIENT_PREFIX=${CLIENT_PREFIX}" "-DCLIENT_NAMESPACE=${CLIENT_NAMESPACE}" + "-DADDITIONAL_CLIENTGEN_ARGS=${ADDITIONAL_CLIENTGEN_ARGS}" + -P ${GRAPHQL_UPDATE_CLIENT_FILES_SCRIPT} + DEPENDS ${SCHEMA_GRAPHQL} ${REQUEST_GRAPHQL} ${GRAPHQL_UPDATE_CLIENT_FILES_SCRIPT} cppgraphqlgen::clientgen + COMMENT "Generating ${CLIENT_TARGET} client" + VERBATIM) +endfunction() + +function(add_graphql_client_target CLIENT_TARGET) + add_custom_target(${CLIENT_TARGET}_update_client ALL + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${CLIENT_TARGET}_client_files) + + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${CLIENT_TARGET}_client_files) + file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/${CLIENT_TARGET}_client_files CLIENT_FILES) + add_library(${CLIENT_TARGET}_client STATIC ${CLIENT_FILES}) + add_dependencies(${CLIENT_TARGET}_client ${CLIENT_TARGET}_update_client) + target_include_directories(${CLIENT_TARGET}_client PUBLIC $) + target_link_libraries(${CLIENT_TARGET}_client PUBLIC cppgraphqlgen::graphqlclient) + endif() +endfunction() diff --git a/cmake/cppgraphqlgen-update-client-files.cmake b/cmake/cppgraphqlgen-update-client-files.cmake new file mode 100644 index 00000000..fe6fa0cc --- /dev/null +++ b/cmake/cppgraphqlgen-update-client-files.cmake @@ -0,0 +1,60 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +# Normalize the filesystem paths +get_filename_component(CLIENT_SOURCE_DIR ${CLIENT_SOURCE_DIR} ABSOLUTE) +get_filename_component(CLIENT_BINARY_DIR ${CLIENT_BINARY_DIR} ABSOLUTE) +get_filename_component(CLIENTGEN_PROGRAM ${CLIENTGEN_PROGRAM} ABSOLUTE) +get_filename_component(SCHEMA_GRAPHQL "${CLIENT_SOURCE_DIR}/${SCHEMA_GRAPHQL}" ABSOLUTE) +get_filename_component(REQUEST_GRAPHQL "${CLIENT_SOURCE_DIR}/${REQUEST_GRAPHQL}" ABSOLUTE) + +file(MAKE_DIRECTORY ${CLIENT_BINARY_DIR}) + +# Cleanup all of the stale files in the binary directory +file(GLOB PREVIOUS_FILES ${CLIENT_BINARY_DIR}/*.h ${CLIENT_BINARY_DIR}/*.cpp + ${CLIENT_BINARY_DIR}/${CLIENT_TARGET}_client_files) +foreach(PREVIOUS_FILE ${PREVIOUS_FILES}) + file(REMOVE ${PREVIOUS_FILE}) +endforeach() + +set(CLIENTGEN_ARGS "--schema=${SCHEMA_GRAPHQL}" "--request=${REQUEST_GRAPHQL}" "--prefix=${CLIENT_PREFIX}" "--namespace=${CLIENT_NAMESPACE}") +foreach(CLIENTGEN_ARG ${ADDITIONAL_CLIENTGEN_ARGS}) + list(APPEND CLIENTGEN_ARGS ${CLIENTGEN_ARG}) +endforeach() + +# Regenerate the sources in the binary directory +execute_process( + COMMAND ${CLIENTGEN_PROGRAM} ${CLIENTGEN_ARGS} + OUTPUT_FILE ${CLIENT_TARGET}_client_files + WORKING_DIRECTORY ${CLIENT_BINARY_DIR}) + +# Get the up-to-date list of files in the binary directory +set(FILE_NAMES "") +file(GLOB NEW_FILES ${CLIENT_BINARY_DIR}/*.h ${CLIENT_BINARY_DIR}/*.cpp) +foreach(NEW_FILE ${NEW_FILES}) + get_filename_component(NEW_FILE ${NEW_FILE} NAME) + list(APPEND FILE_NAMES "${NEW_FILE}") +endforeach() + +# Don't update the files in the source directory if no files were generated in the binary directory. +if(NOT FILE_NAMES) + message(FATAL_ERROR "Schema generation failed!") +endif() + + # Support if() IN_LIST operator: https://cmake.org/cmake/help/latest/policy/CMP0057.html +cmake_policy(SET CMP0057 NEW) + +# Remove stale files in the source directory +file(GLOB OLD_FILES ${CLIENT_SOURCE_DIR}/*.h ${CLIENT_SOURCE_DIR}/*.cpp) +foreach(OLD_FILE ${OLD_FILES}) + get_filename_component(OLD_FILE ${OLD_FILE} NAME) + if(NOT OLD_FILE IN_LIST FILE_NAMES) + file(REMOVE "${CLIENT_SOURCE_DIR}/${OLD_FILE}") + endif() +endforeach() + +# Copy new and modified files from the binary directory to the source directory +execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CLIENT_BINARY_DIR}/${CLIENT_TARGET}_client_files + ${NEW_FILES} + ${CLIENT_SOURCE_DIR}) diff --git a/cmake/cppgraphqlgen-update-schema-files.cmake b/cmake/cppgraphqlgen-update-schema-files.cmake new file mode 100644 index 00000000..495987f6 --- /dev/null +++ b/cmake/cppgraphqlgen-update-schema-files.cmake @@ -0,0 +1,59 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +# Normalize the filesystem paths +get_filename_component(SCHEMA_SOURCE_DIR ${SCHEMA_SOURCE_DIR} ABSOLUTE) +get_filename_component(SCHEMA_BINARY_DIR ${SCHEMA_BINARY_DIR} ABSOLUTE) +get_filename_component(SCHEMAGEN_PROGRAM ${SCHEMAGEN_PROGRAM} ABSOLUTE) +get_filename_component(SCHEMA_GRAPHQL "${SCHEMA_SOURCE_DIR}/${SCHEMA_GRAPHQL}" ABSOLUTE) + +file(MAKE_DIRECTORY ${SCHEMA_BINARY_DIR}) + +# Cleanup all of the stale files in the binary directory +file(GLOB PREVIOUS_FILES ${SCHEMA_BINARY_DIR}/*.h ${SCHEMA_BINARY_DIR}/*.cpp + ${SCHEMA_BINARY_DIR}/${SCHEMA_TARGET}_schema_files) +foreach(PREVIOUS_FILE ${PREVIOUS_FILES}) + file(REMOVE ${PREVIOUS_FILE}) +endforeach() + +set(SCHEMAGEN_ARGS "--schema=${SCHEMA_GRAPHQL}" "--prefix=${SCHEMA_PREFIX}" "--namespace=${SCHEMA_NAMESPACE}") +foreach(SCHEMAGEN_ARG ${ADDITIONAL_SCHEMAGEN_ARGS}) + list(APPEND SCHEMAGEN_ARGS ${SCHEMAGEN_ARG}) +endforeach() + +# Regenerate the sources in the binary directory +execute_process( + COMMAND ${SCHEMAGEN_PROGRAM} ${SCHEMAGEN_ARGS} + OUTPUT_FILE ${SCHEMA_TARGET}_schema_files + WORKING_DIRECTORY ${SCHEMA_BINARY_DIR}) + +# Get the up-to-date list of files in the binary directory +set(FILE_NAMES "") +file(GLOB NEW_FILES ${SCHEMA_BINARY_DIR}/*.h ${SCHEMA_BINARY_DIR}/*.cpp) +foreach(NEW_FILE ${NEW_FILES}) + get_filename_component(NEW_FILE ${NEW_FILE} NAME) + list(APPEND FILE_NAMES "${NEW_FILE}") +endforeach() + +# Don't update the files in the source directory if no files were generated in the binary directory. +if(NOT FILE_NAMES) + message(FATAL_ERROR "Schema generation failed!") +endif() + + # Support if() IN_LIST operator: https://cmake.org/cmake/help/latest/policy/CMP0057.html +cmake_policy(SET CMP0057 NEW) + +# Remove stale files in the source directory +file(GLOB OLD_FILES ${SCHEMA_SOURCE_DIR}/*.h ${SCHEMA_SOURCE_DIR}/*.cpp) +foreach(OLD_FILE ${OLD_FILES}) + get_filename_component(OLD_FILE ${OLD_FILE} NAME) + if(NOT OLD_FILE IN_LIST FILE_NAMES) + file(REMOVE "${SCHEMA_SOURCE_DIR}/${OLD_FILE}") + endif() +endforeach() + +# Copy new and modified files from the binary directory to the source directory +execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${SCHEMA_BINARY_DIR}/${SCHEMA_TARGET}_schema_files + ${NEW_FILES} + ${SCHEMA_SOURCE_DIR}) diff --git a/cmake/test_coroutine.cpp.in b/cmake/test_coroutine.cpp.in new file mode 100644 index 00000000..9ea6c5ac --- /dev/null +++ b/cmake/test_coroutine.cpp.in @@ -0,0 +1,59 @@ +// This is a dummy program that just needs to compile and link to tell us if +// the C++20 coroutine API is available. Use CMake's configure_file command +// to replace the COROUTINE_HEADER and COROUTINE_NAMESPACE tokens for each +// combination of headers and namespaces which we want to pass to the CMake +// try_compile command. + +#include <@COROUTINE_HEADER@> +#include + +struct task +{ + struct promise_type + { + task get_return_object() noexcept + { + return {}; + } + + @COROUTINE_NAMESPACE@::suspend_never initial_suspend() noexcept + { + return {}; + } + + @COROUTINE_NAMESPACE@::suspend_never final_suspend() noexcept + { + return {}; + } + + void return_void() noexcept + { + promise.set_value(); + } + + void unhandled_exception() + { + promise.set_exception(std::current_exception()); + } + + std::promise promise; + }; + + constexpr bool await_ready() const noexcept + { + return true; + } + + std::future future; +}; + +task test_co_return() +{ + co_return; +} + +int main() +{ + test_co_return().future.get(); + return 0; +} \ No newline at end of file diff --git a/cmake/test_filesystem.cpp b/cmake/test_filesystem.cpp new file mode 100644 index 00000000..240e7d6b --- /dev/null +++ b/cmake/test_filesystem.cpp @@ -0,0 +1,19 @@ +// This is a dummy program that just needs to compile and link to tell us if +// the C++17 std::filesystem API requires any additional libraries. + +#include + +int main() +{ + try + { + throw std::filesystem::filesystem_error("instantiate one to make sure it links", + std::make_error_code(std::errc::function_not_supported)); + } + catch (const std::filesystem::filesystem_error& error) + { + return -1; + } + + return !std::filesystem::temp_directory_path().is_absolute(); +} \ No newline at end of file diff --git a/cmake/test_filesystem.cpp.in b/cmake/test_filesystem.cpp.in deleted file mode 100644 index e29d850d..00000000 --- a/cmake/test_filesystem.cpp.in +++ /dev/null @@ -1,22 +0,0 @@ -// This is a dummy program that just needs to compile and link to tell us if -// the C++17 std::filesystem API is available. Use CMake's configure_file -// command to replace the FILESYSTEM_HEADER and FILESYSTEM_NAMESPACE tokens -// for each combination of headers and namespaces which we want to pass to the -// CMake try_compile command. - -#include <@FILESYSTEM_HEADER@> - -int main() -{ - try - { - throw @FILESYSTEM_NAMESPACE@::filesystem_error("instantiate one to make sure it links", - std::make_error_code(std::errc::function_not_supported)); - } - catch (const @FILESYSTEM_NAMESPACE@::filesystem_error& error) - { - return -1; - } - - return !@FILESYSTEM_NAMESPACE@::temp_directory_path().is_absolute(); -} \ No newline at end of file diff --git a/cmake/version.txt b/cmake/version.txt index 084e244c..0c89fc92 100644 --- a/cmake/version.txt +++ b/cmake/version.txt @@ -1 +1 @@ -3.6.0 \ No newline at end of file +4.0.0 \ No newline at end of file diff --git a/doc/awaitable.md b/doc/awaitable.md new file mode 100644 index 00000000..0d41be36 --- /dev/null +++ b/doc/awaitable.md @@ -0,0 +1,267 @@ +# Awaitable + +## Launch Policy + +In previous versions, this was a `std::launch` enum value used with the +`std::async` standard library function. Now, this is a C++20 `Awaitable`, +specifically a type-erased `graphql::service::await_async` class in +[GraphQLService.h](../include/graphqlservice/GraphQLService.h): +```cpp +// Type-erased awaitable. +class await_async : public coro::suspend_always +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual bool await_ready() const = 0; + virtual void await_suspend(coro::coroutine_handle<> h) const = 0; + virtual void await_resume() const = 0; + }; +... + +public: + // Type-erased explicit constructor for a custom awaitable. + template + explicit await_async(std::shared_ptr pimpl) + : _pimpl { std::make_shared>(std::move(pimpl)) } + { + } + + // Default to immediate synchronous execution. + await_async() + : _pimpl { std::static_pointer_cast( + std::make_shared>(std::make_shared())) } + { + } + + // Implicitly convert a std::launch parameter used with std::async to an awaitable. + await_async(std::launch launch) + : _pimpl { ((launch & std::launch::async) == std::launch::async) + ? std::static_pointer_cast(std::make_shared>( + std::make_shared())) + : std::static_pointer_cast(std::make_shared>( + std::make_shared())) } + { + } +... +}; +``` +For convenience, it will use `graphql::service::await_worker_thread` if you specify `std::launch::async`, +which should have the same behavior as calling `std::async(std::launch::async, ...)` did before. + +If you specify any other flags for `std::launch`, it does not honor them. It will use `coro::suspend_never` +(an alias for `std::suspend_never` or `std::experimental::suspend_never`), which as the name suggests, +continues executing the coroutine without suspending. In other words, `std::launch::deferred` will no +longer defer execution as in previous versions, it will execute immediately. + +There is also a default constructor which also uses `coro::suspend_never`, so that is the default +behavior anywhere that `await_async` is default-initialized with `{}`. + +Other than simplification, the big advantage this brings is in the type-erased template constructor. +If you are using another C++20 library or thread/task pool with coroutine support, you can implement +your own `Awaitable` for it and wrap that in `graphql::service::await_async`. It should automatically +start parallelizing all of its resolvers using your custom scheduler, which can pause and resume the +coroutine when and where it likes. + +## Awaitable Results + +Many APIs which used to return some sort of `std::future` now return an alias for +`graphql::internal::Awaitable<...>`. This template is defined in [Awaitable.h](../include/graphqlservice/internal/Awaitable.h): +```cpp +template +class Awaitable +{ +public: + Awaitable(std::future value) + : _value { std::move(value) } + { + } + + T get() + { + return _value.get(); + } + + struct promise_type + { + Awaitable get_return_object() noexcept + { + return { _promise.get_future() }; + } + + ... + + void return_value(T&& value) noexcept(std::is_nothrow_move_constructible_v) + { + _promise.set_value(std::move(value)); + } + + ... + + private: + std::promise _promise; + + }; + + constexpr bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coro::coroutine_handle<> h) const + { + h.resume(); + } + + T await_resume() + { + return _value.get(); + } + +private: + std::future _value; +}; +``` + +The key details are that it implements the required `promise_type` and `await_` methods so +that you can turn any `co_return` statement into a `std::future`, and it can either +`co_await` for that `std::future` from a coroutine, or call `T get()` to block a regular +function until it completes. + +## AwaitableScalar and AwaitableObject + +In previous versions, `service::FieldResult` created an abstraction over return types `T` and +`std::future`, when returning from a field getter you could return either and it would +implicitly convert that to a `service::FieldResult` which looked and acted like a +`std::future`. + +Now, `service::FieldResult` is replaced with `service::AwaitableScalar` for `scalar` type +fields without a selection set of sub-fields, or `service::AwaitableObject` for `object` +type fields which must have a selection set of sub-fields. The difference between +`service::AwaitableScalar` and `service::AwaitableObject` is that `scalar` type fields can +also return `std::shared_ptr` directly, which bypasses all of the +conversion logic in `service::ModifiedResult` and just validates that the shape of the +`response::Value` matches the `scalar` type with all of its modifiers. These are both defined +in [GraphQLService.h](../include/graphqlservice/GraphQLService.h): +```cpp +// Field accessors may return either a result of T, an awaitable of T, or a std::future, so at +// runtime the implementer may choose to return by value or defer/parallelize expensive operations +// by returning an async future or an awaitable coroutine. +// +// If the overhead of conversion to response::Value is too expensive, scalar type field accessors +// can store and return a std::shared_ptr directly. +template +class AwaitableScalar +{ +public: + template + AwaitableScalar(U&& value) + : _value { std::forward(value) } + { + } + + struct promise_type + { + AwaitableScalar get_return_object() noexcept + { + return { _promise.get_future() }; + } + + ... + + void return_value(const T& value) noexcept(std::is_nothrow_copy_constructible_v) + { + _promise.set_value(value); + } + + void return_value(T&& value) noexcept(std::is_nothrow_move_constructible_v) + { + _promise.set_value(std::move(value)); + } + + ... + + private: + std::promise _promise; + }; + + bool await_ready() const noexcept { ... } + + void await_suspend(coro::coroutine_handle<> h) const { ... } + + T await_resume() + { + ... // Throws std::logic_error("Cannot await std::shared_ptr") if called with that alternative + } + + std::shared_ptr get_value() noexcept + { + ... // Returns an empty std::shared_ptr if called with a different alternative + } + +private: + std::variant, std::shared_ptr> _value; +}; + +// Field accessors may return either a result of T, an awaitable of T, or a std::future, so at +// runtime the implementer may choose to return by value or defer/parallelize expensive operations +// by returning an async future or an awaitable coroutine. +template +class AwaitableObject +{ +public: + template + AwaitableObject(U&& value) + : _value { std::forward(value) } + { + } + + struct promise_type + { + AwaitableObject get_return_object() noexcept + { + return { _promise.get_future() }; + } + + ... + + void return_value(const T& value) noexcept(std::is_nothrow_copy_constructible_v) + { + _promise.set_value(value); + } + + void return_value(T&& value) noexcept(std::is_nothrow_move_constructible_v) + { + _promise.set_value(std::move(value)); + } + + ... + + private: + std::promise _promise; + }; + + bool await_ready() const noexcept { ... } + + void await_suspend(coro::coroutine_handle<> h) const { ... } + + T await_resume() { ... } + +private: + std::variant> _value; +}; +``` + +These types both add a `promise_type` for `T`, but coroutines need their own return type to do that. +Making `service::AwaitableScalar` or `service::AwaitableObject` the return type of a field +getter means you can turn it into a coroutine by just replacing `return` with `co_return`, and +potentially start to `co_await` other awaitables and coroutines. + +Type-erasure made it so you do not need to use a special return type, the type-erased +`Object::Model` type just needs to be able to pass the return result from your field +getter into a constructor for one of these return types. So if you want to implement +your field getters as coroutines, you should still wrap the return type in +`service::AwaitableScalar` or `service::AwaitableObject`. Otherwise, you can remove +the template wrapper from all of your field getters. diff --git a/doc/directives.md b/doc/directives.md index cc13f849..faa67a9b 100644 --- a/doc/directives.md +++ b/doc/directives.md @@ -2,7 +2,7 @@ Directives in GraphQL are extensible annotations which alter the runtime evaluation of a query or which add information to the `schema` definition. -They always begin with an `@`. There are three built-in directives which this +They always begin with an `@`. There are four built-in directives which this library automatically handles: 1. `@include(if: Boolean!)`: Only resolve this field and include it in the @@ -11,9 +11,11 @@ results if the `if` argument evaluates to `true`. results if the `if` argument evaluates to `false`. 3. `@deprecated(reason: String)`: Mark the field or enum value as deprecated through introspection with the specified `reason` string. +4. `@specifiedBy(url: String!)`: Mark the custom scalar type through +introspection as specified by a human readable page at the specified URL. The `schema` can also define custom `directives` which are valid on different elements of the `query`. The library does not handle them automatically, but it -will pass them to the `getField` implementations through the +will pass them to the `getField` implementations through the optional `graphql::service::FieldParams` struct (see [fieldparams.md](fieldparams.md) for more information). \ No newline at end of file diff --git a/doc/fieldparams.md b/doc/fieldparams.md index c098151c..7ca8d7c1 100644 --- a/doc/fieldparams.md +++ b/doc/fieldparams.md @@ -7,31 +7,18 @@ shared state or `directives` from the `query`, so the `resolveField` method also packs that information into a `graphql::service::FieldParams` struct and passes it to every `getField` method as the first parameter. +This parameter is optional. The type-erased implementation of `graphql::service::Object` +for each `Object` type in the schema declares a pair of `methods::ObjectHas::getFieldWithParams` +and `methods::ObjectHas::getField` concepts for each field getter. If the implementation +type supports passing the `graphql::service::FieldParams` struct as the first parameter, +the type-erased `object::Object` invokes the `getFieldWithParams` version, otherwise it +drops the parameter and calls the `getField` version with whatever other field +arguments the schema specified. + ## Details of Field Parameters The `graphql::service::FieldParams` struct is declared in [GraphQLService.h](../include/graphqlservice/GraphQLService.h): ```cpp -// Resolvers may be called in multiple different Operation contexts. -enum class ResolverContext -{ - // Resolving a Query operation. - Query, - - // Resolving a Mutation operation. - Mutation, - - // Adding a Subscription. If you need to prepare to send events for this Subsciption - // (e.g. registering an event sink of your own), this is a chance to do that. - NotifySubscribe, - - // Resolving a Subscription event. - Subscription, - - // Removing a Subscription. If there are no more Subscriptions registered this is an - // opportunity to release resources which are no longer needed. - NotifyUnsubscribe, -}; - // Pass a common bundle of parameters to all of the generated Object::getField accessors in a // SelectionSet struct SelectionSetParams @@ -42,39 +29,61 @@ struct SelectionSetParams // The lifetime of each of these borrowed references is guaranteed until the future returned // by the accessor is resolved or destroyed. They are owned by the OperationData shared pointer. const std::shared_ptr& state; - const response::Value& operationDirectives; - const response::Value& fragmentDefinitionDirectives; + const Directives& operationDirectives; + const std::shared_ptr fragmentDefinitionDirectives; // Fragment directives are shared for all fields in that fragment, but they aren't kept alive // after the call to the last accessor in the fragment. If you need to keep them alive longer, - // you'll need to explicitly copy them into other instances of response::Value. - const response::Value& fragmentSpreadDirectives; - const response::Value& inlineFragmentDirectives; + // you'll need to explicitly copy them into other instances of Directives. + const std::shared_ptr fragmentSpreadDirectives; + const std::shared_ptr inlineFragmentDirectives; // Field error path to this selection set. std::optional errorPath; // Async launch policy for sub-field resolvers. - const std::launch launch = std::launch::deferred; + const await_async launch {}; }; // Pass a common bundle of parameters to all of the generated Object::getField accessors. struct FieldParams : SelectionSetParams { GRAPHQLSERVICE_EXPORT explicit FieldParams( - SelectionSetParams&& selectionSetParams, response::Value&& directives); + SelectionSetParams&& selectionSetParams, Directives directives); // Each field owns its own field-specific directives. Once the accessor returns it will be // destroyed, but you can move it into another instance of response::Value to keep it alive // longer. - response::Value fieldDirectives; + Directives fieldDirectives; }; ``` ### Resolver Context The `SelectionSetParams::resolverContext` enum member informs the `getField` -accessors about what type of operation is being resolved. +accessors about what type of operation is being resolved: +```cpp +// Resolvers may be called in multiple different Operation contexts. +enum class ResolverContext +{ + // Resolving a Query operation. + Query, + + // Resolving a Mutation operation. + Mutation, + + // Adding a Subscription. If you need to prepare to send events for this Subsciption + // (e.g. registering an event sink of your own), this is a chance to do that. + NotifySubscribe, + + // Resolving a Subscription event. + Subscription, + + // Removing a Subscription. If there are no more Subscriptions registered this is an + // opportunity to release resources which are no longer needed. + NotifyUnsubscribe, +}; +``` ### Request State @@ -82,10 +91,10 @@ The `SelectionSetParams::state` member is a reference to the `std::shared_ptr` parameter passed to `Request::resolve` (see [resolvers.md](./resolvers.md) for more info): ```cpp -// The RequestState is nullable, but if you have multiple threads processing requests and there's any -// per-request state that you want to maintain throughout the request (e.g. optimizing or batching -// backend requests), you can inherit from RequestState and pass it to Request::resolve to correlate the -// asynchronous/recursive callbacks and accumulate state in it. +// The RequestState is nullable, but if you have multiple threads processing requests and there's +// any per-request state that you want to maintain throughout the request (e.g. optimizing or +// batching backend requests), you can inherit from RequestState and pass it to Request::resolve to +// correlate the asynchronous/recursive callbacks and accumulate state in it. struct RequestState : std::enable_shared_from_this { }; @@ -96,16 +105,27 @@ struct RequestState : std::enable_shared_from_this Each of the `directives` members contains the values of the `directives` and any of their arguments which were in effect at that scope of the `query`. Implementers may inspect those values in the call to `getField` and alter their -behavior based on those custom `directives`. +behavior based on those custom `directives`: +```cpp +// Directive order matters, and some of them are repeatable. So rather than passing them in a +// response::Value, pass directives in something like the underlying response::MapType which +// preserves the order of the elements without complete uniqueness. +using Directives = std::vector>; + +// Traversing a fragment spread adds a new set of directives. +using FragmentDefinitionDirectiveStack = std::list>; +using FragmentSpreadDirectiveStack = std::list; +``` As noted in the comments, the `fragmentSpreadDirectives` and -`inlineFragmentDirectives` are borrowed `const` references, shared accross -calls to multiple `getField` methods, but they will not be kept alive after -the relevant `SelectionSet` has been resolved. The `fieldDirectives` member is -passed by value and is not shared with other `getField` method calls, but it -will not be kept alive after that call returns. It's up to the implementer to -capture the values in these `directives` which they might need for asynchronous -evaulation after the call to the current `getField` method has returned. +`inlineFragmentDirectives` are stacks of directives passed down through nested +inline fragments and fragment spreads. The `Directives` object for each frame of +the stack is shared accross calls to multiple `getField` methods in a single fragment, +but they will be popped from the stack when the last field has been visited. The +`fieldDirectives` member is passed by value and is not shared with other `getField` +method calls. It's up to the implementer to capture the values in these `directives` +which they might need for asynchronous evaulation after the call to the current +`getField` method has returned. The implementer does not need to capture the values of `operationDirectives` or `fragmentDefinitionDirectives` because those are kept alive until the @@ -120,22 +140,17 @@ implementation detail by client code. It automatically propagates through the field resolvers, and if there is a schema exception or one of the `getField` accessors throws another exception derived from `std::exception`, the `graphqlservice` library will automatically add the resulting path to the error -report, accoring to the [spec](http://spec.graphql.org/June2018/#sec-Errors). +report, accoring to the [spec](https://spec.graphql.org/October2021/#sec-Errors). ### Launch Policy -The `graphqlservice` library uses the `SelectionSetParams::launch` parameter to -determine how it should handle async resolvers in the same selection set or -elements in the same list. It is passed from the top-most `resolve`, `deliver`, -or async `subscribe`/`unsubscribe` call. The `getField` accessors get a copy of -this member in their `FieldParams` argument, and they may change their own -behavior based on that, but they cannot alter the launch policy which -`graphqlservice` uses for the resolvers themselves. +See the [Awaitable](./awaitable.md) document for more information about +`service::await_async`. ## Related Documents 1. The `getField` methods are discussed in more detail in [resolvers.md](./resolvers.md). -2. Built-in and custom `directives` are discussed in [directives.md](./directives.md). -3. Subscription resolvers get called up to 3 times depending on which -`subscribe`/`unsubscribe` overrides you call. See [subscriptions.md](./subscriptions.md) -for more details. \ No newline at end of file +2. Awaitable types are covered in [awaitable.md](./awaitable.md). +3. Built-in and custom `directives` are discussed in [directives.md](./directives.md). +4. Subscription resolvers may be called 2 extra times, inside of subscribe` and `unsubscribe`. +See [subscriptions.md](./subscriptions.md) for more details. \ No newline at end of file diff --git a/doc/json.md b/doc/json.md index 57202daa..8ea8b0c4 100644 --- a/doc/json.md +++ b/doc/json.md @@ -37,4 +37,49 @@ comment in that file for more information: # implementation, and you should set BUILD_GRAPHQLJSON so that the test dependencies know # about your version of graphqljson. option(GRAPHQL_USE_RAPIDJSON "Use RapidJSON for JSON serialization." ON) -``` \ No newline at end of file +``` + +## response::Writer + +You can plug-in a type-erased streaming `response::Writer` to serialize a `response::Value` +to some other output mechanism, without building a single string buffer for the entire +document in memory. For example, you might use this to write directly to a buffered IPC pipe +or network connection: +```cpp +class Writer +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual void start_object() const = 0; + virtual void add_member(const std::string& key) const = 0; + virtual void end_object() const = 0; + + virtual void start_array() const = 0; + virtual void end_arrary() const = 0; + + virtual void write_null() const = 0; + virtual void write_string(const std::string& value) const = 0; + virtual void write_bool(bool value) const = 0; + virtual void write_int(int value) const = 0; + virtual void write_float(double value) const = 0; + }; +... + +public: + template + Writer(std::unique_ptr writer) + : _concept { std::static_pointer_cast( + std::make_shared>(std::move(writer))) } + { + } + + GRAPHQLRESPONSE_EXPORT void write(Value value) const; +}; +``` + +Internally, this is what `graphqljson` uses to implement `response::toJSON` with RapidJSON. +It wraps a `rapidjson::Writer` in `response::Writer` and then writes into a +`rapidjson::StringBuffer` through that. diff --git a/doc/parsing.md b/doc/parsing.md index 018e0fbb..300fe816 100644 --- a/doc/parsing.md +++ b/doc/parsing.md @@ -49,7 +49,7 @@ mix of executable and schema definitions. There are `parseSchemaString` and `parseSchemaFile` functions which do the opposite, but unless you are building additional tooling on top of the `graphqlpeg` library, you will probably not need them. They have only been used -by `schemagen` in this project. +by `schemagen` and `clientgen` in this project. ## Encoding diff --git a/doc/resolvers.md b/doc/resolvers.md index c43fe36d..a294392d 100644 --- a/doc/resolvers.md +++ b/doc/resolvers.md @@ -34,21 +34,37 @@ schema { Executing a query or mutation starts by calling `Request::resolve` from [GraphQLService.h](../include/graphqlservice/GraphQLService.h): ```cpp -GRAPHQLSERVICE_EXPORT std::future resolve( - const std::shared_ptr& state, peg::ast& query, - const std::string& operationName, response::Value&& variables) const; +GRAPHQLSERVICE_EXPORT response::AwaitableValue resolve(RequestResolveParams params) const; ``` -By default, the `std::future` results are resolved on-demand but synchronously, -using `std::launch::deferred` with the `std::async` function. You can also use -an override of `Request::resolve` which lets you substitute the -`std::launch::async` option to begin executing the query on multiple threads -in parallel: + +The `RequestResolveParams` struct is defined in the same header: ```cpp -GRAPHQLSERVICE_EXPORT std::future resolve(std::launch launch, - const std::shared_ptr& state, peg::ast& query, - const std::string& operationName, response::Value&& variables) const; +struct RequestResolveParams +{ + // Required query information. + peg::ast& query; + std::string_view operationName {}; + response::Value variables { response::Type::Map }; + + // Optional async execution awaitable. + await_async launch; + + // Optional sub-class of RequestState which will be passed to each resolver and field accessor. + std::shared_ptr state; +}; ``` +The only parameter which cannot be default initialized is `query`. + +The `service::await_async` launch policy is described in [awaitable.md](./awaitable.md). +By default, the resolvers will run on the same thread synchronously. + +The `response::AwaitableValue` return type is a type alias in [GraphQLResponse.h](../include/graphqlservice/GraphQLResponse.h): +```cpp +using AwaitableValue = internal::Awaitable; +``` +The `internal::Awaitable` template is described in [awaitable.md](./awaitable.md). + ### `graphql::service::Request` and `graphql::::Operations` Anywhere in the documentation where it mentions `graphql::service::Request` @@ -56,45 +72,104 @@ methods, the concrete type will actually be `graphql::::Operations`. This `class` is defined by `schemagen` and inherits from `graphql::service::Request`. It links the top-level objects for the custom schema to the `resolve` methods on its base class. See -`graphql::today::Operations` in [TodaySchema.h](../samples/separate/TodaySchema.h) +`graphql::today::Operations` in [TodaySchema.h](../samples/today/schema/TodaySchema.h) for an example. ## Generated Service Schema -The `schemagen` tool generates C++ types in the `graphql::::object` -namespace with `resolveField` methods for each `field` which parse the -arguments from the `query` and automatically dispatch the call to a `getField` -virtual method to retrieve the `field` result. On `object` types, it will also -recursively call the `resolvers` for each of the `fields` in the nested -`SelectionSet`. See for example the generated -`graphql::today::object::Appointment` object from the `today` sample in -[AppointmentObject.h](../samples/separate/AppointmentObject.h). +The `schemagen` tool generates type-erased C++ types in the `graphql::::object` +namespace with `resolveField` methods for each `field` which parse the arguments from +the `query` and automatically dispatch the call to a `getField` method on the +implementation type to retrieve the `field` result. On `object` types, it will also +recursively call the `resolvers` for each of the `fields` in the nested `SelectionSet`. +See for example the generated `graphql::today::object::Appointment` object from the `today` +sample in [AppointmentObject.cpp](../samples/today/schema/AppointmentObject.cpp): ```cpp -std::future resolveId(service::ResolverParams&& params); +service::AwaitableResolver Appointment::resolveId(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} ``` -In this example, the `resolveId` method invokes `getId`: +In this example, the `resolveId` method invokes `Concept::getId(service::FieldParams&&)`, +which is implemented by `Model::getId(service::FieldParams&&)`: ```cpp -virtual service::FieldResult getId(service::FieldParams&& params) const override; +service::AwaitableScalar getId(service::FieldParams&& params) const final +{ + if constexpr (methods::AppointmentHas::getIdWithParams) + { + return { _pimpl->getId(std::move(params)) }; + } + else if constexpr (methods::AppointmentHas::getId) + { + return { _pimpl->getId() }; + } + else + { + throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); + } +} ``` -There are a couple of interesting quirks in this example: -1. The `Appointment object` implements and inherits from the `Node interface`, -which already declared `getId` as a pure-virtual method. That's what the -`override` keyword refers to. -2. This schema was generated with default stub implementations (without the -`schemagen --no-stubs` parameter) which speed up initial development with NYI -(Not Yet Implemented) stubs. With that parameter, there would be no -declaration of `Appointment::getId` since it would inherit a pure-virtual -declaration and the implementer would need to define an override on the -concrete implementation of `graphql::today::object::Appointment`. The NYI stub -will throw a `std::runtime_error`, which the `resolver` converts into an entry -in the `response errors` collection: +There are a couple of interesting points in this example: +1. The `methods::AppointmentHas::getIdWithParams` and +`methods::AppointmentHas::getIdWith` concepts are automatically generated at the top of +[AppointmentObject.h](../samples/today/schema/AppointmentObject.h). The implementation +of the virtual method from the `object::Appointment::Concept` interface uses +`if constexpr (...)` to conditionally compile just one of the 3 method bodies, depending +on whether or not `T` matches those concepts: ```cpp -throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); +namespace methods::AppointmentHas { + +template +concept getIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getId(std::move(params)) } }; +}; + +template +concept getId = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getId() } }; +}; + +... + +} // namespace methods::AppointmentHas +``` +2. This schema was generated with default stub implementations (using the +`schemagen --stubs` parameter) which speeds up initial development with NYI +(Not Yet Implemented) stubs. If the implementation type `T` does not match either +concept, it will still implement this method on `object::Appointment::Model`, but +it will always throw a `std::runtime_error` indicating that the method was not implemented. +Compared to the type-erased objects generated for the [learn](../samples/learn/), such as +[HumanObject.h](../samples/learn/schema/HumanObject.h), without `schemagen --stubs` it +adds a `static_assert` instead, so it will trigger a compile-time error if you do not +implement all of the field getters: +```cpp +service::AwaitableScalar getId(service::FieldParams&& params) const final +{ + if constexpr (methods::HumanHas::getIdWithParams) + { + return { _pimpl->getId(std::move(params)) }; + } + else + { + static_assert(methods::HumanHas::getId, R"msg(Human::getId is not implemented)msg"); + return { _pimpl->getId() }; + } +} ``` Although the `id field` does not take any arguments according to the sample -[schema](../samples/schema.today.graphql), this example also shows how -every `getField` method takes a `graphql::service::FieldParams` struct as -its first parameter. There are more details on this in the [fieldparams.md](./fieldparams.md) -document. \ No newline at end of file +[schema](../samples/today/schema.today.graphql), this example also shows how every `getField` +method on the `object::Appointment::Concept` takes a `graphql::service::FieldParams` struct +as its first parameter from the resolver. If the implementation type can take that parameter +and matches the concept, the `object::Appointment::Model` `getField` method will pass +it through to the implementation type. If it does not, it will silently ignore that +parameter and invoke the implementation type `getField` method without it. There are more +details on this in the [fieldparams.md](./fieldparams.md) document. \ No newline at end of file diff --git a/doc/responses.md b/doc/responses.md index 6c4d9cb1..a1cf432b 100644 --- a/doc/responses.md +++ b/doc/responses.md @@ -7,7 +7,7 @@ As the comment in responses are not technically JSON-specific, although that is probably the most common way of representing them. These are the primitive types that may be represented in GraphQL, as of the -[June 2018 spec](http://spec.graphql.org/June2018/#sec-Serialization-Format): +[October 2021 spec](https://spec.graphql.org/October2021/#sec-Serialization-Format): ```c++ enum class Type : uint8_t diff --git a/doc/subscriptions.md b/doc/subscriptions.md index 7dd3e9bb..3ee8f02a 100644 --- a/doc/subscriptions.md +++ b/doc/subscriptions.md @@ -8,48 +8,84 @@ provide a way to register callbacks when adding a subscription, and you can define trigger conditions when delivering an update to selectively dispatch the subscriptions to those listeners. -## Adding/Removing a Listener +## Adding a Listener -Subscriptions are created or removed by calling the `Request::subscribe` -and `Request::unsubscribe` methods in [GraphQLService.h](../include/graphqlservice/GraphQLService.h): +Subscriptions are created by calling the `Request::subscribe` method in +[GraphQLService.h](../include/graphqlservice/GraphQLService.h): ```cpp -GRAPHQLSERVICE_EXPORT SubscriptionKey subscribe( - SubscriptionParams&& params, SubscriptionCallback&& callback); -GRAPHQLSERVICE_EXPORT std::future subscribe( - std::launch launch, SubscriptionParams&& params, SubscriptionCallback&& callback); - -GRAPHQLSERVICE_EXPORT void unsubscribe(SubscriptionKey key); -GRAPHQLSERVICE_EXPORT std::future unsubscribe(std::launch launch, SubscriptionKey key); +GRAPHQLSERVICE_EXPORT AwaitableSubscribe subscribe(RequestSubscribeParams params); ``` -You need to fill in a `SubscriptionParams` struct with the [parsed](./parsing.md) -query and any other relevant operation parameters: + +You need to fill in a `RequestSubscribeParams` struct with the subscription event +callback, the [parsed](./parsing.md) `query` and any other relevant operation parameters: ```cpp -// You can still sub-class RequestState and use that in the state parameter to Request::subscribe -// to add your own state to the service callbacks that you receive while executing the subscription -// query. -struct SubscriptionParams +struct RequestSubscribeParams { - std::shared_ptr state; + // Callback which receives the event data. + SubscriptionCallback callback; + + // Required query information. peg::ast query; - std::string operationName; - response::Value variables; + std::string operationName {}; + response::Value variables { response::Type::Map }; + + // Optional async execution awaitable. + await_async launch; + + // Optional sub-class of RequestState which will be passed to each resolver and field accessor. + std::shared_ptr state; }; ``` + The `SubscriptionCallback` signature is: ```cpp // Subscription callbacks receive the response::Value representing the result of evaluating the // SelectionSet against the payload. -using SubscriptionCallback = std::function)>; +using SubscriptionCallback = std::function; +``` + +The `service::await_async` launch policy is described in [awaitable.md](./awaitable.md). +By default, the resolvers will run on the same thread synchronously. + +The `std::shared_ptr` state is described in [fieldparams.md](./fieldparams.md). + +The `AwaitableSubscribe` return type is a type alias in +[GraphQLResponse.h](../include/graphqlservice/GraphQLResponse.h): +```cpp +using AwaitableSubscribe = internal::Awaitable; +``` +The `internal::Awaitable` template is described in [awaitable.md](./awaitable.md). + +## Removing a Listener + +Subscriptions are removed by calling the `Request::unsubscribe` method in +[GraphQLService.h](../include/graphqlservice/GraphQLService.h): +```cpp +GRAPHQLSERVICE_EXPORT AwaitableUnsubscribe unsubscribe(RequestUnsubscribeParams params); +``` + +You need to fill in a `RequestUnsubscribeParams` struct with the `SubscriptionKey` +returned by `Request::subscribe` in `AwaitableSubscribe`: +```cpp +struct RequestUnsubscribeParams +{ + // Key returned by a previous call to subscribe. + SubscriptionKey key; + + // Optional async execution awaitable. + await_async launch; +}; ``` +The `service::await_async` launch policy is described in [awaitable.md](./awaitable.md). +By default, the resolvers will run on the same thread synchronously. + ## `ResolverContext::NotifySubscribe` and `ResolverContext::NotifyUnsubscribe` -If you use the async version of `subscribe` and `unsubscribe` which take a -`std::launch` parameter, and you provide a default instance of the -`Subscription` object to the `Request`/`Operations` constructor, you will get -additional callbacks with the `ResolverContext::NotifySubscribe` and -`ResolverContext::NotifyUnsubscribe` values for the -`FieldParams::resolverContext` member. These are passed by the async +If you provide a default instance of the `Subscription` object to the `Request`/ +`Operations` constructor, you will get additional callbacks with the +`ResolverContext::NotifySubscribe` and `ResolverContext::NotifyUnsubscribe` values +for the `FieldParams::resolverContext` member. These are passed by the `subscribe` and `unsubscribe` calls to the default subscription object, and they provide an opportunity to acquire or release resources that are required to implement the subscription. @@ -62,81 +98,77 @@ event payload for a `deliver` call will be resolved with ## Delivering Subscription Updates -If you pass an empty `std::shared_ptr` for the `subscriptionObject` -parameter, `deliver` will fall back to resolving the query against the default -`Subscription` object passed to the `Request`/`Operations` constructor. If both -`Subscription` object parameters are empty, `deliver` will throw an exception. - -There are currently five `Request::deliver` overrides you can choose from when -sending updates to any subscribed listeners. The first one is the simplest, -it will evaluate each subscribed query against the `subscriptionObject` -parameter (which should match the `Subscription` type in the `schema`). It will -unconditionally invoke every subscribed `SubscriptionCallback` callback with -the response to its query: +If you pass an empty `std::shared_ptr` for the +`subscriptionObject` parameter, `deliver` will fall back to resolving the query +against the default `Subscription` object passed to the `Request`/`Operations` +constructor. If both `Subscription` object parameters are empty, `deliver` +will throw an exception: ```cpp -GRAPHQLSERVICE_EXPORT void deliver( - const SubscriptionName& name, const std::shared_ptr& subscriptionObject) const; +GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(RequestDeliverParams params) const; ``` -The second override adds argument filtering. It will look at the field -arguments in the subscription `query`, and if all of the required parameters -in the `arguments` parameter are present and are an exact match it will -dispatch the callback to that subscription: +The `Request::deliver` method determines which subscriptions should receive +an event based on several factors, which makes the `RequestDeliverParams` struct +more complicated: ```cpp -GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, - const SubscriptionArguments& arguments, - const std::shared_ptr& subscriptionObject) const; -``` +struct RequestDeliverParams +{ + // Deliver to subscriptions on this field. + std::string_view field; -The third override adds directive filtering. It will look at both the field -arguments and the directives with their own arguments in the subscription -`query`, and if all of them match it will dispatch the callback to that -subscription: -```cpp -GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, - const SubscriptionArguments& arguments, const SubscriptionArguments& directives, - const std::shared_ptr& subscriptionObject) const; + // Optional filter to control which subscriptions will receive the event. If not specified, + // every subscription on this field will receive the event and evaluate their queries. + RequestDeliverFilter filter; + + // Optional async execution awaitable. + await_async launch; + + // Optional override for the default Subscription operation object. + std::shared_ptr subscriptionObject; +}; ``` -The last two overrides let you customize the the way that the required -arguments and directives are matched. Instead of an exact match or making all -of the arguments required, it will dispatch the callback if the `apply` -function parameters return true for every required field and directive in the -subscription `query`. +First, the `Request::deliver` method selects only the subscriptions which are listening +to events for this field. Then, if you specify the `RequestDeliverFilter`, it filters the set +of subscriptions down to the ones which it matches: ```cpp -GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const std::shared_ptr& subscriptionObject) const; -GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const SubscriptionFilterCallback& applyDirectives, - const std::shared_ptr& subscriptionObject) const; +// Deliver to a specific subscription key, or apply custom criteria for the field name, arguments, +// and directives in the Subscription query. +using RequestDeliverFilter = std::optional>; ``` -By default, `deliver` invokes all of the `SubscriptionCallback` listeners with -`std::future` payloads which are resolved on-demand but synchronously, using -`std::launch::deferred` with the `std::async` function. There's also a version -of each overload which lets you substitute the `std::launch::async` option to -begin executing the queries and invoke the callbacks on multiple threads in -parallel: +The simplest filter is the `SubscriptionKey`. If you specify that, and the subscription is +listening to `field` events, `Request::deliver` will only deliver to that one subscription. + +The `SubscriptionFilter struct` adds alternative filters for the field arguments and any field +directives which might have been specified in the subscription query. For each one, you can either +specify a callback which will test each argument or directive, or you can specify a set of required +arguments or directives which must all be present: ```cpp -GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, - const std::shared_ptr& subscriptionObject) const; -GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionArguments& arguments, - const std::shared_ptr& subscriptionObject) const; -GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionArguments& arguments, const SubscriptionArguments& directives, - const std::shared_ptr& subscriptionObject) const; -GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const std::shared_ptr& subscriptionObject) const; -GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const SubscriptionFilterCallback& applyDirectives, - const std::shared_ptr& subscriptionObject) const; +using SubscriptionArguments = std::map; +using SubscriptionArgumentFilterCallback = std::function; +using SubscriptionDirectiveFilterCallback = std::function; + +struct SubscriptionFilter +{ + // Optional field argument filter, which can either be a set of required arguments, or a + // callback which returns true if the arguments match custom criteria. + std::optional> + arguments; + + // Optional field directives filter, which can either be a set of required directives and + // arguments, or a callback which returns true if the directives match custom criteria. + std::optional> directives; +}; ``` +The `service::await_async` launch policy is described in [awaitable.md](./awaitable.md). +By default, the resolvers will run on the same thread synchronously. + +The optional `std::shared_ptr subscriptionObject` parameter can override the +default Subscription operation object passed to the `Operations` constructor, or supply +one if no default instance was included. + ## Handling Multiple Operation Types Some service implementations (e.g. Apollo over HTTP) use a single pipe to diff --git a/include/ClientGenerator.h b/include/ClientGenerator.h index 36def4f5..f725d4e8 100644 --- a/include/ClientGenerator.h +++ b/include/ClientGenerator.h @@ -19,7 +19,7 @@ struct GeneratorPaths struct GeneratorOptions { - const std::optional paths; + const GeneratorPaths paths; const bool verbose = false; }; diff --git a/include/SchemaGenerator.h b/include/SchemaGenerator.h index 1b617286..58ced48f 100644 --- a/include/SchemaGenerator.h +++ b/include/SchemaGenerator.h @@ -18,10 +18,9 @@ struct GeneratorPaths struct GeneratorOptions { - const std::optional paths; + const GeneratorPaths paths; const bool verbose = false; - const bool separateFiles = false; - const bool noStubs = false; + const bool stubs = false; const bool noIntrospection = false; }; @@ -29,7 +28,7 @@ class Generator { public: // Initialize the generator with the introspection schema or a custom GraphQL schema. - explicit Generator(std::optional&& customSchema, GeneratorOptions&& options); + explicit Generator(SchemaOptions&& schemaOptions, GeneratorOptions&& options); // Run the generator and return a list of filenames that were output. std::vector Build() const noexcept; @@ -38,10 +37,12 @@ class Generator std::string getHeaderDir() const noexcept; std::string getSourceDir() const noexcept; std::string getHeaderPath() const noexcept; - std::string getObjectHeaderPath() const noexcept; std::string getSourcePath() const noexcept; bool outputHeader() const noexcept; + void outputInterfaceDeclaration(std::ostream& headerFile, std::string_view cppType) const; + void outputObjectImplements(std::ostream& headerFile, const ObjectType& objectType) const; + void outputObjectStubs(std::ostream& headerFile, const ObjectType& objectType) const; void outputObjectDeclaration( std::ostream& headerFile, const ObjectType& objectType, bool isQueryType) const; std::string getFieldDeclaration(const InputField& inputField) const noexcept; @@ -49,9 +50,17 @@ class Generator std::string getResolverDeclaration(const OutputField& outputField) const noexcept; bool outputSource() const noexcept; + void outputInterfaceImplementation(std::ostream& sourceFile, std::string_view cppType) const; + void outputInterfaceIntrospection( + std::ostream& sourceFile, const InterfaceType& interfaceType) const; + void outputUnionIntrospection(std::ostream& sourceFile, const UnionType& unionType) const; void outputObjectImplementation( std::ostream& sourceFile, const ObjectType& objectType, bool isQueryType) const; void outputObjectIntrospection(std::ostream& sourceFile, const ObjectType& objectType) const; + void outputIntrospectionInterfaces(std::ostream& sourceFile, std::string_view cppType, + const std::vector& interfaces) const; + void outputIntrospectionFields( + std::ostream& sourceFile, std::string_view cppType, const OutputFieldList& fields) const; std::string getArgumentDefaultValue( size_t level, const response::Value& defaultValue) const noexcept; std::string getArgumentDeclaration(const InputField& argument, const char* prefixToken, @@ -71,7 +80,6 @@ class Generator const std::string _headerDir; const std::string _sourceDir; const std::string _headerPath; - const std::string _objectHeaderPath; const std::string _sourcePath; }; diff --git a/include/SchemaLoader.h b/include/SchemaLoader.h index cbd81698..1cae7d2d 100644 --- a/include/SchemaLoader.h +++ b/include/SchemaLoader.h @@ -48,6 +48,7 @@ struct ScalarType { std::string_view type; std::string_view description; + std::string_view specifiedByURL; }; using ScalarTypeList = std::vector; @@ -113,6 +114,7 @@ using InputTypeList = std::vector; struct Directive { std::string_view name; + bool isRepeatable = false; std::vector locations; InputFieldList arguments; std::string_view description; @@ -174,6 +176,7 @@ struct InterfaceType { std::string_view type; std::string_view cppType; + std::vector interfaces; OutputFieldList fields; std::string_view description; }; @@ -209,15 +212,17 @@ struct SchemaOptions const std::string schemaFilename; const std::string filenamePrefix; const std::string schemaNamespace; + const bool isIntrospection = false; }; class SchemaLoader { public: // Initialize the loader with the introspection schema or a custom GraphQL schema. - explicit SchemaLoader(std::optional&& customSchema); + explicit SchemaLoader(SchemaOptions&& schemaOptions); bool isIntrospection() const noexcept; + std::string_view getSchemaDescription() const noexcept; std::string_view getFilenamePrefix() const noexcept; std::string_view getSchemaNamespace() const noexcept; @@ -264,6 +269,7 @@ class SchemaLoader void visitSchemaDefinition(const peg::ast_node& schemaDefinition); void visitSchemaExtension(const peg::ast_node& schemaExtension); void visitScalarTypeDefinition(const peg::ast_node& scalarTypeDefinition); + void visitScalarTypeExtension(const peg::ast_node& scalarTypeExtension); void visitEnumTypeDefinition(const peg::ast_node& enumTypeDefinition); void visitEnumTypeExtension(const peg::ast_node& enumTypeExtension); void visitInputObjectTypeDefinition(const peg::ast_node& inputObjectTypeDefinition); @@ -276,6 +282,8 @@ class SchemaLoader void visitObjectTypeExtension(const peg::ast_node& objectTypeExtension); void visitDirectiveDefinition(const peg::ast_node& directiveDefinition); + static void blockReservedName( + std::string_view name, std::optional position = std::nullopt); static OutputFieldList getOutputFields(const peg::ast_node::children_t& fields); static InputFieldList getInputFields(const peg::ast_node::children_t& fields); @@ -285,14 +293,22 @@ class SchemaLoader const std::optional& accessor); void fixupInputFieldList(InputFieldList& fields); void reorderInputTypeDependencies(); + void validateImplementedInterfaces() const; + const InterfaceType& findInterfaceType( + std::string_view typeName, std::string_view interfaceName) const; + void validateInterfaceFields(std::string_view typeName, + std::string_view interfaceName, const OutputFieldList& typeFields) const; + void validateTransitiveInterfaces( + std::string_view typeName, const std::vector& interfaces) const; static const std::string_view s_introspectionNamespace; static const BuiltinTypeMap s_builtinTypes; static const CppTypeMap s_builtinCppTypes; static const std::string_view s_scalarCppType; - const std::optional _customSchema; + const SchemaOptions _schemaOptions; const bool _isIntrospection; + std::string_view _schemaDescription; std::string_view _schemaNamespace; peg::ast _ast; diff --git a/include/Validation.h b/include/Validation.h index 692d2f6e..f9a11f3c 100644 --- a/include/Validation.h +++ b/include/Validation.h @@ -37,6 +37,7 @@ using ValidateDirectiveArguments = internal::string_view_map; struct ValidateDirective { + bool isRepeatable = false; internal::sorted_set locations; ValidateDirectiveArguments arguments; }; @@ -79,17 +80,16 @@ struct ValidateArgumentMap internal::string_view_map values; }; -using ValidateArgumentVariant = std::variant; +using ValidateArgumentVariant = std::variant; struct ValidateArgumentValue { ValidateArgumentValue(ValidateArgumentVariable&& value); - ValidateArgumentValue(response::IntType value); - ValidateArgumentValue(response::FloatType value); + ValidateArgumentValue(int value); + ValidateArgumentValue(double value); ValidateArgumentValue(std::string_view value); - ValidateArgumentValue(response::BooleanType value); + ValidateArgumentValue(bool value); ValidateArgumentValue(ValidateArgumentEnumValue&& value); ValidateArgumentValue(ValidateArgumentList&& value); ValidateArgumentValue(ValidateArgumentMap&& value); @@ -170,7 +170,7 @@ class ValidateVariableTypeVisitor class ValidateExecutableVisitor { public: - GRAPHQLSERVICE_EXPORT ValidateExecutableVisitor(const std::shared_ptr& schema); + GRAPHQLSERVICE_EXPORT ValidateExecutableVisitor(std::shared_ptr schema); GRAPHQLSERVICE_EXPORT void visit(const peg::ast_node& root); @@ -251,6 +251,7 @@ class ValidateExecutableVisitor VariableSet _referencedVariables; FragmentSet _fragmentStack; size_t _fieldCount = 0; + size_t _introspectionFieldCount = 0; TypeFields _typeFields; InputTypeFields _inputTypeFields; ValidateType _scopedType; diff --git a/include/graphqlservice/GraphQLClient.h b/include/graphqlservice/GraphQLClient.h index 48933811..efdfe3be 100644 --- a/include/graphqlservice/GraphQLClient.h +++ b/include/graphqlservice/GraphQLClient.h @@ -34,13 +34,13 @@ namespace graphql::client { // Errors may specify the line number and column number where the error occurred. struct ErrorLocation { - response::IntType line {}; - response::IntType column {}; + int line {}; + int column {}; }; // Errors may specify a path to the field which triggered the error. The path consists of // field names and the indices of elements in a list. -using ErrorPathSegment = std::variant; +using ErrorPathSegment = std::variant; // Error returned from the service. struct Error @@ -59,7 +59,7 @@ struct ServiceResponse }; // Split a service response into separate ServiceResponse data and errors members. -GRAPHQLCLIENT_EXPORT ServiceResponse parseServiceResponse(response::Value&& response); +GRAPHQLCLIENT_EXPORT ServiceResponse parseServiceResponse(response::Value response); // GraphQL types are nullable by default, but they may be wrapped with non-null or list types. // Since nullability is a more special case in C++, we invert the default and apply that modifier @@ -141,27 +141,23 @@ struct ModifiedVariable // Convenient type aliases for testing, generated code won't actually use these. These are also // the specializations which are implemented in the GraphQLClient library, other specializations // for input types should be generated in schemagen. -using IntVariable = ModifiedVariable; -using FloatVariable = ModifiedVariable; -using StringVariable = ModifiedVariable; -using BooleanVariable = ModifiedVariable; +using IntVariable = ModifiedVariable; +using FloatVariable = ModifiedVariable; +using StringVariable = ModifiedVariable; +using BooleanVariable = ModifiedVariable; using IdVariable = ModifiedVariable; using ScalarVariable = ModifiedVariable; #ifdef GRAPHQL_DLLEXPORTS // Export all of the built-in converters template <> -GRAPHQLCLIENT_EXPORT response::Value ModifiedVariable::serialize( - response::IntType&& value); +GRAPHQLCLIENT_EXPORT response::Value ModifiedVariable::serialize(int&& value); template <> -GRAPHQLCLIENT_EXPORT response::Value ModifiedVariable::serialize( - response::FloatType&& value); +GRAPHQLCLIENT_EXPORT response::Value ModifiedVariable::serialize(double&& value); template <> -GRAPHQLCLIENT_EXPORT response::Value ModifiedVariable::serialize( - response::StringType&& value); +GRAPHQLCLIENT_EXPORT response::Value ModifiedVariable::serialize(std::string&& value); template <> -GRAPHQLCLIENT_EXPORT response::Value ModifiedVariable::serialize( - response::BooleanType&& value); +GRAPHQLCLIENT_EXPORT response::Value ModifiedVariable::serialize(bool&& value); template <> GRAPHQLCLIENT_EXPORT response::Value ModifiedVariable::serialize( response::IdType&& value); @@ -192,12 +188,12 @@ struct ModifiedResponse }; // Parse a single value of the response document. - static Type parse(response::Value&& response); + static Type parse(response::Value response); // Peel off the none modifier. If it's included, it should always be last in the list. template static typename std::enable_if_t - parse(response::Value&& response) + parse(response::Value response) { return parse(std::move(response)); } @@ -206,7 +202,7 @@ struct ModifiedResponse template static typename std::enable_if_t::type>> - parse(response::Value&& response) + parse(response::Value response) { if (response.type() == response::Type::Null) { @@ -221,7 +217,7 @@ struct ModifiedResponse template static typename std::enable_if_t::type>> - parse(response::Value&& response) + parse(response::Value response) { std::vector::type> result; @@ -245,33 +241,29 @@ struct ModifiedResponse // Convenient type aliases for testing, generated code won't actually use these. These are also // the specializations which are implemented in the GraphQLClient library, other specializations // for output types should be generated in schemagen. -using IntResponse = ModifiedResponse; -using FloatResponse = ModifiedResponse; -using StringResponse = ModifiedResponse; -using BooleanResponse = ModifiedResponse; +using IntResponse = ModifiedResponse; +using FloatResponse = ModifiedResponse; +using StringResponse = ModifiedResponse; +using BooleanResponse = ModifiedResponse; using IdResponse = ModifiedResponse; using ScalarResponse = ModifiedResponse; #ifdef GRAPHQL_DLLEXPORTS // Export all of the built-in converters template <> -GRAPHQLCLIENT_EXPORT response::IntType ModifiedResponse::parse( - response::Value&& response); +GRAPHQLCLIENT_EXPORT int ModifiedResponse::parse(response::Value response); template <> -GRAPHQLCLIENT_EXPORT response::FloatType ModifiedResponse::parse( - response::Value&& response); +GRAPHQLCLIENT_EXPORT double ModifiedResponse::parse(response::Value response); template <> -GRAPHQLCLIENT_EXPORT response::StringType ModifiedResponse::parse( - response::Value&& response); +GRAPHQLCLIENT_EXPORT std::string ModifiedResponse::parse(response::Value response); template <> -GRAPHQLCLIENT_EXPORT response::BooleanType ModifiedResponse::parse( - response::Value&& response); +GRAPHQLCLIENT_EXPORT bool ModifiedResponse::parse(response::Value response); template <> GRAPHQLCLIENT_EXPORT response::IdType ModifiedResponse::parse( - response::Value&& response); + response::Value response); template <> GRAPHQLCLIENT_EXPORT response::Value ModifiedResponse::parse( - response::Value&& response); + response::Value response); #endif // GRAPHQL_DLLEXPORTS } // namespace graphql::client diff --git a/include/graphqlservice/GraphQLResponse.h b/include/graphqlservice/GraphQLResponse.h index c9cf580f..09a6f020 100644 --- a/include/graphqlservice/GraphQLResponse.h +++ b/include/graphqlservice/GraphQLResponse.h @@ -18,6 +18,8 @@ #endif // !GRAPHQL_DLLEXPORTS // clang-format on +#include "graphqlservice/internal/Awaitable.h" + #include #include #include @@ -28,7 +30,7 @@ namespace graphql::response { // GraphQL responses are not technically JSON-specific, although that is probably the most common // way of representing them. These are the primitive types that may be represented in GraphQL, as -// of the [June 2018 spec](http://spec.graphql.org/June2018/#sec-Serialization-Format). +// of the [October 2021 spec](https://spec.graphql.org/October2021/#sec-Serialization-Format). enum class Type : uint8_t { Map, // JSON Object @@ -129,6 +131,8 @@ struct Value GRAPHQLRESPONSE_EXPORT Value(Value&& other) noexcept; GRAPHQLRESPONSE_EXPORT explicit Value(const Value& other); + GRAPHQLRESPONSE_EXPORT Value(std::shared_ptr other) noexcept; + GRAPHQLRESPONSE_EXPORT Value& operator=(Value&& rhs) noexcept; Value& operator=(const Value& rhs) = delete; @@ -175,27 +179,6 @@ struct Value template typename ValueTypeTraits::release_type release(); - // Compatibility wrappers - template - [[deprecated("Use the unqualified Value::set<> specialization instead of specializing on the " - "r-value reference.")]] void - set(typename std::enable_if_t, ReferenceType> value) - { - set>(std::move(value)); - } - - template - [[deprecated("Use the unqualified Value::get<> specialization instead of specializing on the " - "const reference.")]] - typename std::enable_if_t< - std::is_lvalue_reference_v< - ReferenceType> && std::is_const_v>, - ReferenceType> - get() const - { - return get>(); - } - private: // Type::Map struct MapData @@ -232,8 +215,12 @@ struct Value std::unique_ptr scalar; }; + using SharedData = std::shared_ptr; + using TypeData = std::variant; + FloatType, EnumData, ScalarData, SharedData>; + + const TypeData& data() const noexcept; TypeData _data; }; @@ -280,6 +267,104 @@ template <> GRAPHQLRESPONSE_EXPORT IdType Value::release(); #endif // GRAPHQL_DLLEXPORTS +using AwaitableValue = internal::Awaitable; + +class Writer +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual void start_object() const = 0; + virtual void add_member(const std::string& key) const = 0; + virtual void end_object() const = 0; + + virtual void start_array() const = 0; + virtual void end_arrary() const = 0; + + virtual void write_null() const = 0; + virtual void write_string(const std::string& value) const = 0; + virtual void write_bool(bool value) const = 0; + virtual void write_int(int value) const = 0; + virtual void write_float(double value) const = 0; + }; + + template + struct Model : Concept + { + Model(std::unique_ptr&& pimpl) + : _pimpl { std::move(pimpl) } + { + } + + void start_object() const final + { + _pimpl->start_object(); + } + + void add_member(const std::string& key) const final + { + _pimpl->add_member(key); + } + + void end_object() const final + { + _pimpl->end_object(); + } + + void start_array() const final + { + _pimpl->start_array(); + } + + void end_arrary() const final + { + _pimpl->end_arrary(); + } + + void write_null() const final + { + _pimpl->write_null(); + } + + void write_string(const std::string& value) const final + { + _pimpl->write_string(value); + } + + void write_bool(bool value) const final + { + _pimpl->write_bool(value); + } + + void write_int(int value) const final + { + _pimpl->write_int(value); + } + + void write_float(double value) const final + { + _pimpl->write_float(value); + } + + private: + std::unique_ptr _pimpl; + }; + + const std::shared_ptr _concept; + +public: + template + Writer(std::unique_ptr writer) + : _concept { std::static_pointer_cast( + std::make_shared>(std::move(writer))) } + { + } + + GRAPHQLRESPONSE_EXPORT void write(Value value) const; +}; + } // namespace graphql::response #endif // GRAPHQLRESPONSE_H diff --git a/include/graphqlservice/GraphQLService.h b/include/graphqlservice/GraphQLService.h index 285686e1..1f08e3d3 100644 --- a/include/graphqlservice/GraphQLService.h +++ b/include/graphqlservice/GraphQLService.h @@ -21,9 +21,11 @@ #include "graphqlservice/GraphQLParse.h" #include "graphqlservice/GraphQLResponse.h" +#include "graphqlservice/internal/Awaitable.h" #include "graphqlservice/internal/SortedMap.h" #include "graphqlservice/internal/Version.h" +#include #include #include #include @@ -35,8 +37,8 @@ #include #include #include -#include #include +#include #include #include @@ -146,6 +148,112 @@ enum class ResolverContext NotifyUnsubscribe, }; +// Resume coroutine execution on a worker thread. +struct await_worker_thread : coro::suspend_always +{ + void await_suspend(coro::coroutine_handle<> h) const + { + std::thread( + [](coro::coroutine_handle<>&& h) noexcept { + h.resume(); + }, + std::move(h)) + .detach(); + } +}; + +// Type-erased awaitable. +class await_async : public coro::suspend_always +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual bool await_ready() const = 0; + virtual void await_suspend(coro::coroutine_handle<> h) const = 0; + virtual void await_resume() const = 0; + }; + + template + struct Model : Concept + { + Model(std::shared_ptr&& pimpl) + : _pimpl { std::move(pimpl) } + { + } + + bool await_ready() const final + { + return _pimpl->await_ready(); + } + + void await_suspend(coro::coroutine_handle<> h) const final + { + _pimpl->await_suspend(std::move(h)); + } + + void await_resume() const final + { + _pimpl->await_resume(); + } + + private: + std::shared_ptr _pimpl; + }; + + const std::shared_ptr _pimpl; + +public: + // Type-erased explicit constructor for a custom awaitable. + template + explicit await_async(std::shared_ptr pimpl) + : _pimpl { std::make_shared>(std::move(pimpl)) } + { + } + + // Default to immediate synchronous execution. + await_async() + : _pimpl { std::static_pointer_cast( + std::make_shared>(std::make_shared())) } + { + } + + // Implicitly convert a std::launch parameter used with std::async to an awaitable. + await_async(std::launch launch) + : _pimpl { ((launch & std::launch::async) == std::launch::async) + ? std::static_pointer_cast(std::make_shared>( + std::make_shared())) + : std::static_pointer_cast(std::make_shared>( + std::make_shared())) } + { + } + + bool await_ready() const + { + return _pimpl->await_ready(); + } + + void await_suspend(coro::coroutine_handle<> h) const + { + _pimpl->await_suspend(std::move(h)); + } + + void await_resume() const + { + _pimpl->await_resume(); + } +}; + +// Directive order matters, and some of them are repeatable. So rather than passing them in a +// response::Value, pass directives in something like the underlying response::MapType which +// preserves the order of the elements without complete uniqueness. +using Directives = std::vector>; + +// Traversing a fragment spread adds a new set of directives. +using FragmentDefinitionDirectiveStack = std::list>; +using FragmentSpreadDirectiveStack = std::list; + // Pass a common bundle of parameters to all of the generated Object::getField accessors in a // SelectionSet struct SelectionSetParams @@ -156,66 +264,262 @@ struct SelectionSetParams // The lifetime of each of these borrowed references is guaranteed until the future returned // by the accessor is resolved or destroyed. They are owned by the OperationData shared pointer. const std::shared_ptr& state; - const response::Value& operationDirectives; - const response::Value& fragmentDefinitionDirectives; + const Directives& operationDirectives; + const std::shared_ptr fragmentDefinitionDirectives; // Fragment directives are shared for all fields in that fragment, but they aren't kept alive // after the call to the last accessor in the fragment. If you need to keep them alive longer, - // you'll need to explicitly copy them into other instances of response::Value. - const response::Value& fragmentSpreadDirectives; - const response::Value& inlineFragmentDirectives; + // you'll need to explicitly copy them into other instances of Directives. + const std::shared_ptr fragmentSpreadDirectives; + const std::shared_ptr inlineFragmentDirectives; // Field error path to this selection set. std::optional errorPath; // Async launch policy for sub-field resolvers. - const std::launch launch = std::launch::deferred; + const await_async launch {}; }; // Pass a common bundle of parameters to all of the generated Object::getField accessors. struct FieldParams : SelectionSetParams { GRAPHQLSERVICE_EXPORT explicit FieldParams( - SelectionSetParams&& selectionSetParams, response::Value&& directives); - - [[deprecated( - "Use the FieldParams constructor overload which takes a SelectionSet r-value " - "reference instead.")]] GRAPHQLSERVICE_EXPORT explicit FieldParams(const SelectionSetParams& - selectionSetParams, - response::Value&& directives); + SelectionSetParams&& selectionSetParams, Directives directives); // Each field owns its own field-specific directives. Once the accessor returns it will be // destroyed, but you can move it into another instance of response::Value to keep it alive // longer. - response::Value fieldDirectives; + Directives fieldDirectives; +}; + +// Field accessors may return either a result of T, an awaitable of T, or a std::future, so at +// runtime the implementer may choose to return by value or defer/parallelize expensive operations +// by returning an async future or an awaitable coroutine. +// +// If the overhead of conversion to response::Value is too expensive, scalar type field accessors +// can store and return a std::shared_ptr directly. +template +class AwaitableScalar +{ +public: + template + AwaitableScalar(U&& value) + : _value { std::forward(value) } + { + } + + struct promise_type + { + AwaitableScalar get_return_object() noexcept + { + return { _promise.get_future() }; + } + + coro::suspend_never initial_suspend() const noexcept + { + return {}; + } + + coro::suspend_never final_suspend() const noexcept + { + return {}; + } + + void return_value(const T& value) noexcept(std::is_nothrow_copy_constructible_v) + { + _promise.set_value(value); + } + + void return_value(T&& value) noexcept(std::is_nothrow_move_constructible_v) + { + _promise.set_value(std::move(value)); + } + + void unhandled_exception() noexcept + { + _promise.set_exception(std::current_exception()); + } + + private: + std::promise _promise; + }; + + bool await_ready() const noexcept + { + return std::visit( + [](const auto& value) noexcept { + using value_type = std::decay_t; + + if constexpr (std::is_same_v) + { + return true; + } + else if constexpr (std::is_same_v>) + { + using namespace std::literals; + + return value.wait_for(0s) != std::future_status::timeout; + } + else if constexpr (std::is_same_v>) + { + return true; + } + }, + _value); + } + + void await_suspend(coro::coroutine_handle<> h) const + { + std::thread( + [this](coro::coroutine_handle<> h) noexcept { + std::get>(_value).wait(); + h.resume(); + }, + std::move(h)) + .detach(); + } + + T await_resume() + { + return std::visit( + [](auto&& value) -> T { + using value_type = std::decay_t; + + if constexpr (std::is_same_v) + { + return T { std::move(value) }; + } + else if constexpr (std::is_same_v>) + { + return value.get(); + } + else if constexpr (std::is_same_v>) + { + throw std::logic_error("Cannot await std::shared_ptr"); + } + }, + std::move(_value)); + } + + std::shared_ptr get_value() noexcept + { + return std::visit( + [](auto&& value) noexcept { + using value_type = std::decay_t; + std::shared_ptr result; + + if constexpr (std::is_same_v>) + { + result = std::move(value); + } + + return result; + }, + std::move(_value)); + } + +private: + std::variant, std::shared_ptr> _value; }; -// Field accessors may return either a result of T or a std::future, so at runtime the -// implementer may choose to return by value or defer/parallelize expensive operations by returning -// an async future. +// Field accessors may return either a result of T, an awaitable of T, or a std::future, so at +// runtime the implementer may choose to return by value or defer/parallelize expensive operations +// by returning an async future or an awaitable coroutine. template -class FieldResult +class AwaitableObject { public: template - FieldResult(U&& value) + AwaitableObject(U&& value) : _value { std::forward(value) } { } - T get() + struct promise_type { - if (std::holds_alternative>(_value)) + AwaitableObject get_return_object() noexcept { - return std::get>(std::move(_value)).get(); + return { _promise.get_future() }; } - return std::get(std::move(_value)); + coro::suspend_never initial_suspend() const noexcept + { + return {}; + } + + coro::suspend_never final_suspend() const noexcept + { + return {}; + } + + void return_value(const T& value) noexcept(std::is_nothrow_copy_constructible_v) + { + _promise.set_value(value); + } + + void return_value(T&& value) noexcept(std::is_nothrow_move_constructible_v) + { + _promise.set_value(std::move(value)); + } + + void unhandled_exception() noexcept + { + _promise.set_exception(std::current_exception()); + } + + private: + std::promise _promise; + }; + + bool await_ready() const noexcept + { + return std::visit( + [](const auto& value) noexcept { + using value_type = std::decay_t; + + if constexpr (std::is_same_v) + { + return true; + } + else if constexpr (std::is_same_v>) + { + using namespace std::literals; + + return value.wait_for(0s) != std::future_status::timeout; + } + }, + _value); + } + + void await_suspend(coro::coroutine_handle<> h) const + { + std::thread( + [this](coro::coroutine_handle<> h) noexcept { + std::get>(_value).wait(); + h.resume(); + }, + std::move(h)) + .detach(); } - bool is_future() const noexcept + T await_resume() { - return std::holds_alternative>(_value); + return std::visit( + [](auto&& value) -> T { + using value_type = std::decay_t; + + if constexpr (std::is_same_v) + { + return T { std::move(value) }; + } + else if constexpr (std::is_same_v>) + { + return value.get(); + } + }, + std::move(_value)); } private: @@ -232,11 +536,11 @@ class Fragment std::string_view getType() const; const peg::ast_node& getSelection() const; - const response::Value& getDirectives() const; + const Directives& getDirectives() const; private: std::string_view _type; - response::Value _directives; + Directives _directives; std::reference_wrapper _selection; }; @@ -251,9 +555,9 @@ using FragmentMap = internal::string_view_map; struct ResolverParams : SelectionSetParams { GRAPHQLSERVICE_EXPORT explicit ResolverParams(const SelectionSetParams& selectionSetParams, - const peg::ast_node& field, std::string&& fieldName, response::Value&& arguments, - response::Value&& fieldDirectives, const peg::ast_node* selection, - const FragmentMap& fragments, const response::Value& variables); + const peg::ast_node& field, std::string&& fieldName, response::Value arguments, + Directives fieldDirectives, const peg::ast_node* selection, const FragmentMap& fragments, + const response::Value& variables); GRAPHQLSERVICE_EXPORT schema_location getLocation() const; @@ -261,7 +565,7 @@ struct ResolverParams : SelectionSetParams const peg::ast_node& field; std::string fieldName; response::Value arguments { response::Type::Map }; - response::Value fieldDirectives { response::Type::Map }; + Directives fieldDirectives; const peg::ast_node* selection; // These values remain unchanged for the entire operation, but they're passed to each of the @@ -278,7 +582,8 @@ struct ResolverResult std::list errors; }; -using Resolver = std::function(ResolverParams&&)>; +using AwaitableResolver = internal::Awaitable; +using Resolver = std::function; using ResolverMap = internal::string_view_map; // GraphQL types are nullable by default, but they may be wrapped with non-null or list types. @@ -319,7 +624,7 @@ struct ModifiedArgument static Type convert(const response::Value& value); // Call convert on this type without any modifiers. - static Type require(const std::string& name, const response::Value& arguments) + static Type require(std::string_view name, const response::Value& arguments) { try { @@ -358,9 +663,11 @@ struct ModifiedArgument // Peel off the none modifier. If it's included, it should always be last in the list. template - static typename std::enable_if_t - require(const std::string& name, const response::Value& arguments) + static typename std::enable_if_t require( + std::string_view name, const response::Value& arguments) { + static_assert(sizeof...(Other) == 0, "None modifier should always be last"); + // Just call through to the non-template method without the modifiers. return require(name, arguments); } @@ -369,7 +676,7 @@ struct ModifiedArgument template static typename std::enable_if_t::type> - require(const std::string& name, const response::Value& arguments) + require(std::string_view name, const response::Value& arguments) { const auto& valueItr = arguments.find(name); @@ -388,7 +695,7 @@ struct ModifiedArgument template static typename std::enable_if_t::type> - require(const std::string& name, const response::Value& arguments) + require(std::string_view name, const response::Value& arguments) { const auto& values = arguments[name]; typename ArgumentTraits::type result(values.size()); @@ -397,7 +704,7 @@ struct ModifiedArgument std::transform(elements.cbegin(), elements.cend(), result.begin(), - [&name](const response::Value& element) { + [name](const response::Value& element) { response::Value single(response::Type::Map); single.emplace_back(std::string { name }, response::Value(element)); @@ -411,7 +718,7 @@ struct ModifiedArgument // Wrap require with modifiers in a try/catch block. template static std::pair::type, bool> find( - const std::string& name, const response::Value& arguments) noexcept + std::string_view name, const response::Value& arguments) noexcept { try { @@ -427,27 +734,24 @@ struct ModifiedArgument // Convenient type aliases for testing, generated code won't actually use these. These are also // the specializations which are implemented in the GraphQLService library, other specializations // for input types should be generated in schemagen. -using IntArgument = ModifiedArgument; -using FloatArgument = ModifiedArgument; -using StringArgument = ModifiedArgument; -using BooleanArgument = ModifiedArgument; +using IntArgument = ModifiedArgument; +using FloatArgument = ModifiedArgument; +using StringArgument = ModifiedArgument; +using BooleanArgument = ModifiedArgument; using IdArgument = ModifiedArgument; using ScalarArgument = ModifiedArgument; #ifdef GRAPHQL_DLLEXPORTS // Export all of the built-in converters template <> -GRAPHQLSERVICE_EXPORT response::IntType ModifiedArgument::convert( - const response::Value& value); +GRAPHQLSERVICE_EXPORT int ModifiedArgument::convert(const response::Value& value); template <> -GRAPHQLSERVICE_EXPORT response::FloatType ModifiedArgument::convert( - const response::Value& value); +GRAPHQLSERVICE_EXPORT double ModifiedArgument::convert(const response::Value& value); template <> -GRAPHQLSERVICE_EXPORT response::StringType ModifiedArgument::convert( +GRAPHQLSERVICE_EXPORT std::string ModifiedArgument::convert( const response::Value& value); template <> -GRAPHQLSERVICE_EXPORT response::BooleanType ModifiedArgument::convert( - const response::Value& value); +GRAPHQLSERVICE_EXPORT bool ModifiedArgument::convert(const response::Value& value); template <> GRAPHQLSERVICE_EXPORT response::IdType ModifiedArgument::convert( const response::Value& value); @@ -467,12 +771,12 @@ using TypeNames = internal::string_view_set; class Object : public std::enable_shared_from_this { public: - GRAPHQLSERVICE_EXPORT explicit Object(TypeNames&& typeNames, ResolverMap&& resolvers); + GRAPHQLSERVICE_EXPORT explicit Object(TypeNames&& typeNames, ResolverMap&& resolvers) noexcept; GRAPHQLSERVICE_EXPORT virtual ~Object() = default; - GRAPHQLSERVICE_EXPORT std::future resolve( - const SelectionSetParams& selectionSetParams, const peg::ast_node& selection, - const FragmentMap& fragments, const response::Value& variables) const; + GRAPHQLSERVICE_EXPORT AwaitableResolver resolve(const SelectionSetParams& selectionSetParams, + const peg::ast_node& selection, const FragmentMap& fragments, + const response::Value& variables) const; GRAPHQLSERVICE_EXPORT bool matchesType(std::string_view typeName) const; @@ -486,7 +790,7 @@ class Object : public std::enable_shared_from_this GRAPHQLSERVICE_EXPORT virtual void beginSelectionSet(const SelectionSetParams& params) const; GRAPHQLSERVICE_EXPORT virtual void endSelectionSet(const SelectionSetParams& params) const; - std::mutex _resolverMutex {}; + mutable std::mutex _resolverMutex {}; private: TypeNames _typeNames; @@ -511,7 +815,8 @@ struct ModifiedResult std::vector::type>, typename std::conditional_t, std::shared_ptr, U>>>; - using future_type = FieldResult&&; + using future_type = typename std::conditional_t, + AwaitableObject, AwaitableScalar>; }; template @@ -521,41 +826,44 @@ struct ModifiedResult typename std::conditional_t, std::shared_ptr, U>; using future_type = typename std::conditional_t, - FieldResult>, FieldResult>&&; + AwaitableObject>, AwaitableScalar>; }; // Convert a single value of the specified type to JSON. - static std::future convert( - typename ResultTraits::future_type result, ResolverParams&& params); + static AwaitableResolver convert( + typename ResultTraits::future_type result, ResolverParams params); // Peel off the none modifier. If it's included, it should always be last in the list. template - static typename std::enable_if_t && std::is_base_of_v, - std::future> - convert(FieldResult::type>&& result, ResolverParams&& params) + AwaitableResolver> + convert(AwaitableObject::type> result, ResolverParams params) { // Call through to the Object specialization with a static_pointer_cast for subclasses of // Object. + static_assert(sizeof...(Other) == 0, "None modifier should always be last"); static_assert(std::is_same_v, typename ResultTraits::type>, "this is the derived object type"); - auto resultFuture = std::async( - std::launch::deferred, - [](auto&& objectType) { - return std::static_pointer_cast(objectType.get()); - }, - std::move(result)); - return ModifiedResult::convert(std::move(resultFuture), std::move(params)); + co_await params.launch; + + auto awaitedResult = co_await ModifiedResult::convert( + std::static_pointer_cast(co_await result), + std::move(params)); + + co_return std::move(awaitedResult); } // Peel off the none modifier. If it's included, it should always be last in the list. template - static typename std::enable_if_t || !std::is_base_of_v), - std::future> - convert(typename ResultTraits::future_type result, ResolverParams&& params) + AwaitableResolver> + convert(typename ResultTraits::future_type result, ResolverParams params) { + static_assert(sizeof...(Other) == 0, "None modifier should always be last"); + // Just call through to the partial specialization without the modifier. return convert(std::move(result), std::move(params)); } @@ -564,175 +872,137 @@ struct ModifiedResult template static typename std::enable_if_t, typename ResultTraits::type>, - std::future> - convert(typename ResultTraits::future_type result, - ResolverParams&& params) + AwaitableResolver> + convert( + typename ResultTraits::future_type result, ResolverParams params) { - return std::async( - std::launch::deferred, - [](auto&& wrappedFuture, ResolverParams&& wrappedParams) { - auto wrappedResult = wrappedFuture.get(); + co_await params.launch; - if (!wrappedResult) - { - return ResolverResult {}; - } + auto awaitedResult = co_await std::move(result); - std::promise::type> promise; + if (!awaitedResult) + { + co_return ResolverResult {}; + } - promise.set_value(std::move(wrappedResult)); + auto modifiedResult = + co_await ModifiedResult::convert(std::move(awaitedResult), std::move(params)); - return ModifiedResult::convert(promise.get_future(), - std::move(wrappedParams)) - .get(); - }, - std::move(result), - std::move(params)); + co_return modifiedResult; } // Peel off nullable modifiers for anything else, which should all be std::optional. template static typename std::enable_if_t, typename ResultTraits::type>, - std::future> - convert(typename ResultTraits::future_type result, - ResolverParams&& params) + AwaitableResolver> + convert( + typename ResultTraits::future_type result, ResolverParams params) { static_assert(std::is_same_v::type>, typename ResultTraits::type>, "this is the optional version"); - return std::async( - std::launch::deferred, - [](auto&& wrappedFuture, ResolverParams&& wrappedParams) { - auto wrappedResult = wrappedFuture.get(); + if constexpr (!std::is_base_of_v) + { + auto value = result.get_value(); - if (!wrappedResult) - { - return ResolverResult {}; - } + if (value) + { + ModifiedResult::validateScalar(*value); + co_return ResolverResult { response::Value { + std::shared_ptr { std::move(value) } } }; + } + } - std::promise::type> promise; + co_await params.launch; - promise.set_value(std::move(*wrappedResult)); + auto awaitedResult = co_await std::move(result); - return ModifiedResult::convert(promise.get_future(), - std::move(wrappedParams)) - .get(); - }, - std::move(result), + if (!awaitedResult) + { + co_return ResolverResult {}; + } + + auto modifiedResult = co_await ModifiedResult::convert(std::move(*awaitedResult), std::move(params)); + + co_return modifiedResult; } // Peel off list modifiers. template - static typename std::enable_if_t> - convert(typename ResultTraits::future_type result, - ResolverParams&& params) - { - return std::async( - params.launch, - [](auto&& wrappedFuture, ResolverParams&& wrappedParams) { - auto wrappedResult = wrappedFuture.get(); - std::vector> children; - const auto parentPath = wrappedParams.errorPath; - - children.reserve(wrappedResult.size()); - wrappedParams.errorPath = std::make_optional(field_path { - parentPath ? std::make_optional(std::cref(*parentPath)) : std::nullopt, - path_segment { size_t { 0 } } }); - - using vector_type = std::decay_t; - - if constexpr (!std::is_same_v, - typename vector_type::value_type>) - { - // Special handling for std::vector<> specializations which don't return a - // reference to the underlying type, i.e. std::vector on many platforms. - // Copy the values from the std::vector<> rather than moving them. - for (typename vector_type::value_type entry : wrappedResult) - { - children.push_back(ModifiedResult::convert(std::move(entry), - ResolverParams(wrappedParams))); - ++std::get(wrappedParams.errorPath->segment); - } - } - else - { - for (auto& entry : wrappedResult) - { - children.push_back(ModifiedResult::convert(std::move(entry), - ResolverParams(wrappedParams))); - ++std::get(wrappedParams.errorPath->segment); - } - } + static typename std::enable_if_t convert( + typename ResultTraits::future_type result, ResolverParams params) + { + if constexpr (!std::is_base_of_v) + { + auto value = result.get_value(); - ResolverResult document { response::Value { response::Type::List } }; + if (value) + { + ModifiedResult::validateScalar(*value); + co_return ResolverResult { response::Value { + std::shared_ptr { std::move(value) } } }; + } + } - document.data.reserve(children.size()); - std::get(wrappedParams.errorPath->segment) = 0; + std::vector children; + const auto parentPath = params.errorPath; - for (auto& child : children) - { - try - { - auto value = child.get(); - - document.data.emplace_back(std::move(value.data)); - - if (!value.errors.empty()) - { - document.errors.splice(document.errors.end(), value.errors); - } - } - catch (schema_exception& scx) - { - auto errors = scx.getStructuredErrors(); - - if (!errors.empty()) - { - document.errors.splice(document.errors.end(), errors); - } - } - catch (const std::exception& ex) - { - std::ostringstream message; - - message << "Field error name: " << wrappedParams.fieldName - << " unknown error: " << ex.what(); - - document.errors.emplace_back(schema_error { message.str(), - wrappedParams.getLocation(), - buildErrorPath(wrappedParams.errorPath) }); - } - - ++std::get(wrappedParams.errorPath->segment); - } + co_await params.launch; - return document; - }, - std::move(result), - std::move(params)); - } + auto awaitedResult = co_await std::move(result); -private: - using ResolverCallback = - std::function::type&&, const ResolverParams&)>; + children.reserve(awaitedResult.size()); + params.errorPath = std::make_optional( + field_path { parentPath ? std::make_optional(std::cref(*parentPath)) : std::nullopt, + path_segment { size_t { 0 } } }); - static std::future resolve(typename ResultTraits::future_type result, - ResolverParams&& params, ResolverCallback&& resolver) - { - static_assert(!std::is_base_of_v, - "ModfiedResult needs special handling"); + using vector_type = std::decay_t; - auto buildResult = [](auto&& resultFuture, - ResolverParams&& paramsFuture, - ResolverCallback&& resolverFuture) noexcept { - ResolverResult document; + if constexpr (!std::is_same_v, + typename vector_type::value_type>) + { + // Special handling for std::vector<> specializations which don't return a + // reference to the underlying type, i.e. std::vector on many platforms. + // Copy the values from the std::vector<> rather than moving them. + for (typename vector_type::value_type entry : awaitedResult) + { + children.push_back( + ModifiedResult::convert(std::move(entry), ResolverParams(params))); + ++std::get(params.errorPath->segment); + } + } + else + { + for (auto& entry : awaitedResult) + { + children.push_back( + ModifiedResult::convert(std::move(entry), ResolverParams(params))); + ++std::get(params.errorPath->segment); + } + } + + ResolverResult document { response::Value { response::Type::List } }; + document.data.reserve(children.size()); + std::get(params.errorPath->segment) = 0; + + for (auto& child : children) + { try { - document.data = resolverFuture(resultFuture.get(), paramsFuture); + co_await params.launch; + + auto value = co_await std::move(child); + + document.data.emplace_back(std::move(value.data)); + + if (!value.errors.empty()) + { + document.errors.splice(document.errors.end(), value.errors); + } } catch (schema_exception& scx) { @@ -747,41 +1017,118 @@ struct ModifiedResult { std::ostringstream message; - message << "Field name: " << paramsFuture.fieldName + message << "Field error name: " << params.fieldName << " unknown error: " << ex.what(); document.errors.emplace_back(schema_error { message.str(), - paramsFuture.getLocation(), - buildErrorPath(paramsFuture.errorPath) }); + params.getLocation(), + buildErrorPath(params.errorPath) }); } - return document; - }; + ++std::get(params.errorPath->segment); + } + + co_return document; + } + +private: + // Validate a single scalar value is the expected type. + static void validateScalar(const response::Value& value); + + // Peel off the none modifier. If it's included, it should always be last in the list. + template + static void validateScalar( + typename std::enable_if_t value) + { + static_assert(sizeof...(Other) == 0, "None modifier should always be last"); + + // Just call through to the partial specialization without the modifier. + validateScalar(value); + } - if (result.is_future()) + // Peel off nullable modifiers. + template + static void validateScalar( + typename std::enable_if_t value) + { + if (value.type() != response::Type::Null) { - return std::async(std::launch::deferred, - std::move(buildResult), - std::move(result), - std::move(params), - std::move(resolver)); + ModifiedResult::validateScalar(value); } + } - std::promise promise; + // Peel off list modifiers. + template + static void validateScalar( + typename std::enable_if_t value) + { + if (value.type() != response::Type::List) + { + throw schema_exception { { R"ex(not a valid List value)ex" } }; + } - promise.set_value(buildResult(std::move(result), std::move(params), std::move(resolver))); + for (size_t i = 0; i < value.size(); ++i) + { + ModifiedResult::validateScalar(value[i]); + } + } - return promise.get_future(); + using ResolverCallback = + std::function::type, const ResolverParams&)>; + + static AwaitableResolver resolve(typename ResultTraits::future_type result, + ResolverParams params, ResolverCallback&& resolver) + { + static_assert(!std::is_base_of_v, + "ModfiedResult needs special handling"); + + auto value = result.get_value(); + + if (value) + { + ModifiedResult::validateScalar(*value); + co_return ResolverResult { response::Value { std::shared_ptr { std::move(value) } } }; + } + + auto pendingResolver = std::move(resolver); + ResolverResult document; + + try + { + co_await params.launch; + document.data = pendingResolver(co_await result, params); + } + catch (schema_exception& scx) + { + auto errors = scx.getStructuredErrors(); + + if (!errors.empty()) + { + document.errors.splice(document.errors.end(), errors); + } + } + catch (const std::exception& ex) + { + std::ostringstream message; + + message << "Field name: " << params.fieldName << " unknown error: " << ex.what(); + + document.errors.emplace_back(schema_error { message.str(), + params.getLocation(), + buildErrorPath(params.errorPath) }); + } + + co_return document; } }; // Convenient type aliases for testing, generated code won't actually use these. These are also // the specializations which are implemented in the GraphQLService library, other specializations // for output types should be generated in schemagen. -using IntResult = ModifiedResult; -using FloatResult = ModifiedResult; -using StringResult = ModifiedResult; -using BooleanResult = ModifiedResult; +using IntResult = ModifiedResult; +using FloatResult = ModifiedResult; +using StringResult = ModifiedResult; +using BooleanResult = ModifiedResult; using IdResult = ModifiedResult; using ScalarResult = ModifiedResult; using ObjectResult = ModifiedResult; @@ -789,41 +1136,135 @@ using ObjectResult = ModifiedResult; #ifdef GRAPHQL_DLLEXPORTS // Export all of the built-in converters template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params); +GRAPHQLSERVICE_EXPORT AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params); +template <> +GRAPHQLSERVICE_EXPORT AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params); +template <> +GRAPHQLSERVICE_EXPORT AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params); +template <> +GRAPHQLSERVICE_EXPORT AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params); +template <> +GRAPHQLSERVICE_EXPORT AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params); +template <> +GRAPHQLSERVICE_EXPORT AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params); +template <> +GRAPHQLSERVICE_EXPORT AwaitableResolver ModifiedResult::convert( + AwaitableObject> result, ResolverParams params); + +// Export all of the scalar value validation methods template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params); +GRAPHQLSERVICE_EXPORT void ModifiedResult::validateScalar(const response::Value& value); template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params); +GRAPHQLSERVICE_EXPORT void ModifiedResult::validateScalar(const response::Value& value); template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params); +GRAPHQLSERVICE_EXPORT void ModifiedResult::validateScalar( + const response::Value& value); template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params); +GRAPHQLSERVICE_EXPORT void ModifiedResult::validateScalar(const response::Value& value); template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params); +GRAPHQLSERVICE_EXPORT void ModifiedResult::validateScalar( + const response::Value& value); template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( - FieldResult>&& result, ResolverParams&& params); +GRAPHQLSERVICE_EXPORT void ModifiedResult::validateScalar( + const response::Value& value); #endif // GRAPHQL_DLLEXPORTS -using TypeMap = internal::string_view_map>; +// Subscription callbacks receive the response::Value representing the result of evaluating the +// SelectionSet against the payload. +using SubscriptionCallback = std::function; + +// Subscriptions are stored in maps using these keys. +using SubscriptionKey = size_t; +using SubscriptionName = std::string; -// You can still sub-class RequestState and use that in the state parameter to Request::subscribe -// to add your own state to the service callbacks that you receive while executing the subscription -// query. -struct SubscriptionParams +using AwaitableSubscribe = internal::Awaitable; +using AwaitableUnsubscribe = internal::Awaitable; +using AwaitableDeliver = internal::Awaitable; + +struct RequestResolveParams { + // Required query information. + peg::ast& query; + std::string_view operationName {}; + response::Value variables { response::Type::Map }; + + // Optional async execution awaitable. + await_async launch; + + // Optional sub-class of RequestState which will be passed to each resolver and field accessor. std::shared_ptr state; +}; + +struct RequestSubscribeParams +{ + // Callback which receives the event data. + SubscriptionCallback callback; + + // Required query information. peg::ast query; - std::string operationName; - response::Value variables; + std::string operationName {}; + response::Value variables { response::Type::Map }; + + // Optional async execution awaitable. + await_async launch; + + // Optional sub-class of RequestState which will be passed to each resolver and field accessor. + std::shared_ptr state; +}; + +struct RequestUnsubscribeParams +{ + // Key returned by a previous call to subscribe. + SubscriptionKey key; + + // Optional async execution awaitable. + await_async launch; +}; + +using SubscriptionArguments = std::map; +using SubscriptionArgumentFilterCallback = std::function; +using SubscriptionDirectiveFilterCallback = std::function; + +struct SubscriptionFilter +{ + // Optional field argument filter, which can either be a set of required arguments, or a + // callback which returns true if the arguments match custom criteria. + std::optional> + arguments; + + // Optional field directives filter, which can either be a set of required directives and + // arguments, or a callback which returns true if the directives match custom criteria. + std::optional> directives; +}; + +// Deliver to a specific subscription key, or apply custom criteria for the field name, arguments, +// and directives in the Subscription query. +using RequestDeliverFilter = std::optional>; + +struct RequestDeliverParams +{ + // Deliver to subscriptions on this field. + std::string_view field; + + // Optional filter to control which subscriptions will receive the event. If not specified, + // every subscription on this field will receive the event and evaluate their queries. + RequestDeliverFilter filter; + + // Optional async execution awaitable. + await_async launch; + + // Optional override for the default Subscription operation object. + std::shared_ptr subscriptionObject; }; +using TypeMap = internal::string_view_map>; + // State which is captured and kept alive until all pending futures have been resolved for an // operation. Note: SelectionSet is the other parameter that gets passed to the top level Object, // it's a borrowed reference to an element in the AST. In the case of query and mutation operations, @@ -832,30 +1273,20 @@ struct SubscriptionParams // already tied to the registration and any pending futures passed to callbacks. struct OperationData : std::enable_shared_from_this { - explicit OperationData(std::shared_ptr&& state, response::Value&& variables, - response::Value&& directives, FragmentMap&& fragments); + explicit OperationData(std::shared_ptr state, response::Value variables, + Directives directives, FragmentMap fragments); std::shared_ptr state; response::Value variables; - response::Value directives; + Directives directives; FragmentMap fragments; }; -// Subscription callbacks receive the response::Value representing the result of evaluating the -// SelectionSet against the payload. -using SubscriptionCallback = std::function)>; -using SubscriptionArguments = std::map; -using SubscriptionFilterCallback = std::function; - -// Subscriptions are stored in maps using these keys. -using SubscriptionKey = size_t; -using SubscriptionName = std::string; - // Registration information for subscription, cached in the Request::subscribe call. struct SubscriptionData : std::enable_shared_from_this { - explicit SubscriptionData(std::shared_ptr&& data, SubscriptionName&& field, - response::Value&& arguments, response::Value&& fieldDirectives, peg::ast&& query, + explicit SubscriptionData(std::shared_ptr data, SubscriptionName&& field, + response::Value arguments, Directives fieldDirectives, peg::ast&& query, std::string&& operationName, SubscriptionCallback&& callback, const peg::ast_node& selection); @@ -863,7 +1294,7 @@ struct SubscriptionData : std::enable_shared_from_this SubscriptionName field; response::Value arguments; - response::Value fieldDirectives; + Directives fieldDirectives; peg::ast query; std::string operationName; SubscriptionCallback callback; @@ -880,7 +1311,7 @@ class Request : public std::enable_shared_from_this { protected: GRAPHQLSERVICE_EXPORT explicit Request( - TypeMap&& operationTypes, const std::shared_ptr& schema); + TypeMap operationTypes, std::shared_ptr schema); GRAPHQLSERVICE_EXPORT virtual ~Request(); public: @@ -889,75 +1320,16 @@ class Request : public std::enable_shared_from_this GRAPHQLSERVICE_EXPORT std::pair findOperationDefinition( peg::ast& query, std::string_view operationName) const; - GRAPHQLSERVICE_EXPORT std::future resolve( - const std::shared_ptr& state, peg::ast& query, - const std::string& operationName, response::Value&& variables) const; - GRAPHQLSERVICE_EXPORT std::future resolve(std::launch launch, - const std::shared_ptr& state, peg::ast& query, - const std::string& operationName, response::Value&& variables) const; - - GRAPHQLSERVICE_EXPORT SubscriptionKey subscribe( - SubscriptionParams&& params, SubscriptionCallback&& callback); - GRAPHQLSERVICE_EXPORT std::future subscribe( - std::launch launch, SubscriptionParams&& params, SubscriptionCallback&& callback); - - GRAPHQLSERVICE_EXPORT void unsubscribe(SubscriptionKey key); - GRAPHQLSERVICE_EXPORT std::future unsubscribe(std::launch launch, SubscriptionKey key); - - GRAPHQLSERVICE_EXPORT void deliver( - const SubscriptionName& name, const std::shared_ptr& subscriptionObject) const; - GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, - const SubscriptionArguments& arguments, - const std::shared_ptr& subscriptionObject) const; - GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, - const SubscriptionArguments& arguments, const SubscriptionArguments& directives, - const std::shared_ptr& subscriptionObject) const; - GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const std::shared_ptr& subscriptionObject) const; - GRAPHQLSERVICE_EXPORT void deliver(const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const SubscriptionFilterCallback& applyDirectives, - const std::shared_ptr& subscriptionObject) const; - - GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, - const std::shared_ptr& subscriptionObject) const; - GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionArguments& arguments, - const std::shared_ptr& subscriptionObject) const; - GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionArguments& arguments, const SubscriptionArguments& directives, - const std::shared_ptr& subscriptionObject) const; - GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const std::shared_ptr& subscriptionObject) const; - GRAPHQLSERVICE_EXPORT void deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const SubscriptionFilterCallback& applyDirectives, - const std::shared_ptr& subscriptionObject) const; - - [[deprecated( - "Use the Request::findOperationDefinition overload which takes a peg::ast reference and " - "string_view instead.")]] GRAPHQLSERVICE_EXPORT std::pair - findOperationDefinition(const peg::ast_node& root, const std::string& operationName) const; - - [[deprecated("Use the Request::resolve overload which takes a peg::ast reference " - "instead.")]] GRAPHQLSERVICE_EXPORT std::future - resolve(const std::shared_ptr& state, const peg::ast_node& root, - const std::string& operationName, response::Value&& variables) const; - [[deprecated("Use the Request::resolve overload which takes a peg::ast reference " - "instead.")]] GRAPHQLSERVICE_EXPORT std::future - resolve(std::launch launch, const std::shared_ptr& state, - const peg::ast_node& root, const std::string& operationName, - response::Value&& variables) const; + GRAPHQLSERVICE_EXPORT response::AwaitableValue resolve(RequestResolveParams params) const; + GRAPHQLSERVICE_EXPORT AwaitableSubscribe subscribe(RequestSubscribeParams params); + GRAPHQLSERVICE_EXPORT AwaitableUnsubscribe unsubscribe(RequestUnsubscribeParams params); + GRAPHQLSERVICE_EXPORT AwaitableDeliver deliver(RequestDeliverParams params) const; private: - std::pair findUnvalidatedOperationDefinition( - const peg::ast_node& root, const std::string& operationName) const; - - std::future resolveUnvalidated(std::launch launch, - const std::shared_ptr& state, const peg::ast_node& root, - const std::string& operationName, response::Value&& variables) const; + SubscriptionKey addSubscription(RequestSubscribeParams&& params); + void removeSubscription(SubscriptionKey key); + std::vector> collectRegistrations( + std::string_view field, RequestDeliverFilter&& filter) const noexcept; const TypeMap _operations; std::unique_ptr _validation; diff --git a/include/graphqlservice/internal/Awaitable.h b/include/graphqlservice/internal/Awaitable.h new file mode 100644 index 00000000..1abca33d --- /dev/null +++ b/include/graphqlservice/internal/Awaitable.h @@ -0,0 +1,162 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef Awaitable_H +#define Awaitable_H + +// clang-format off +#ifdef USE_STD_EXPERIMENTAL_COROUTINE + #include + namespace coro = std::experimental; +#else // !USE_STD_EXPERIMENTAL_COROUTINE + #include + namespace coro = std; +#endif +// clang-format on + +#include +#include + +namespace graphql::internal { + +template +class Awaitable; + +template <> +class Awaitable +{ +public: + Awaitable(std::future value) + : _value { std::move(value) } + { + } + + void get() + { + _value.get(); + } + + struct promise_type + { + Awaitable get_return_object() noexcept + { + return { _promise.get_future() }; + } + + coro::suspend_never initial_suspend() const noexcept + { + return {}; + } + + coro::suspend_never final_suspend() const noexcept + { + return {}; + } + + void return_void() noexcept + { + _promise.set_value(); + } + + void unhandled_exception() noexcept + { + _promise.set_exception(std::current_exception()); + } + + private: + std::promise _promise; + }; + + constexpr bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coro::coroutine_handle<> h) const + { + h.resume(); + } + + void await_resume() + { + _value.get(); + } + +private: + std::future _value; +}; + +template +class Awaitable +{ +public: + Awaitable(std::future value) + : _value { std::move(value) } + { + } + + T get() + { + return _value.get(); + } + + struct promise_type + { + Awaitable get_return_object() noexcept + { + return { _promise.get_future() }; + } + + coro::suspend_never initial_suspend() const noexcept + { + return {}; + } + + coro::suspend_never final_suspend() const noexcept + { + return {}; + } + + void return_value(const T& value) noexcept(std::is_nothrow_copy_constructible_v) + { + _promise.set_value(value); + } + + void return_value(T&& value) noexcept(std::is_nothrow_move_constructible_v) + { + _promise.set_value(std::move(value)); + } + + void unhandled_exception() noexcept + { + _promise.set_exception(std::current_exception()); + } + + private: + std::promise _promise; + }; + + constexpr bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coro::coroutine_handle<> h) const + { + h.resume(); + } + + T await_resume() + { + return _value.get(); + } + +private: + std::future _value; +}; + +} // namespace graphql::internal + +#endif // Awaitable_H diff --git a/include/graphqlservice/internal/Grammar.h b/include/graphqlservice/internal/Grammar.h index 1e95e2d3..f1f3d619 100644 --- a/include/graphqlservice/internal/Grammar.h +++ b/include/graphqlservice/internal/Grammar.h @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // -// This grammar is based on the June 2018 Edition of the GraphQL spec: -// http://spec.graphql.org/June2018/ +// This grammar is based on the October 2021 Edition of the GraphQL spec: +// https://spec.graphql.org/October2021/ #pragma once @@ -59,22 +59,22 @@ void on_first_child(const ast_node& n, std::function&& fu } } -// http://spec.graphql.org/June2018/#sec-Source-Text +// https://spec.graphql.org/October2021/#sec-Source-Text struct source_character : sor, utf8::range<0x0020, 0xFFFF>> { }; -// http://spec.graphql.org/June2018/#sec-Comments +// https://spec.graphql.org/October2021/#sec-Comments struct comment : seq, until> { }; -// http://spec.graphql.org/June2018/#sec-Source-Text.Ignored-Tokens +// https://spec.graphql.org/October2021/#sec-Source-Text.Ignored-Tokens struct ignored : sor, comment> { }; -// http://spec.graphql.org/June2018/#sec-Names +// https://spec.graphql.org/October2021/#sec-Names struct name : identifier { }; @@ -83,12 +83,12 @@ struct variable_name_content : name { }; -// http://spec.graphql.org/June2018/#Variable +// https://spec.graphql.org/October2021/#Variable struct variable_name : if_must, variable_name_content> { }; -// http://spec.graphql.org/June2018/#sec-Null-Value +// https://spec.graphql.org/October2021/#sec-Null-Value struct null_keyword : TAO_PEGTL_KEYWORD("null") { }; @@ -109,12 +109,12 @@ struct escaped_unicode_content : list, escaped_unicode_content> { }; -// http://spec.graphql.org/June2018/#EscapedCharacter +// https://spec.graphql.org/October2021/#EscapedCharacter struct escaped_char : one<'"', '\\', '/', 'b', 'f', 'n', 'r', 't'> { }; @@ -137,7 +137,7 @@ struct string_quote_content { }; -// http://spec.graphql.org/June2018/#StringCharacter +// https://spec.graphql.org/October2021/#StringCharacter struct string_quote : if_must { }; @@ -151,26 +151,42 @@ struct block_escape_sequence : seq }; struct block_quote_character - : plus, not_at, source_character> + : plus, not_at, not_at, + source_character> { }; -struct block_quote_content - : seq>, must> +struct block_quote_empty_line : star, space> { }; -// http://spec.graphql.org/June2018/#BlockStringCharacter +struct block_quote_line_content : plus> +{ +}; + +struct block_quote_line : seq +{ +}; + +struct block_quote_content_lines : opt, eol>> +{ +}; + +struct block_quote_content : seq> +{ +}; + +// https://spec.graphql.org/October2021/#BlockStringCharacter struct block_quote : if_must { }; -// http://spec.graphql.org/June2018/#StringValue +// https://spec.graphql.org/October2021/#StringValue struct string_value : sor { }; -// http://spec.graphql.org/June2018/#NonZeroDigit +// https://spec.graphql.org/October2021/#NonZeroDigit struct nonzero_digit : range<'1', '9'> { }; @@ -179,17 +195,17 @@ struct zero_digit : one<'0'> { }; -// http://spec.graphql.org/June2018/#NegativeSign +// https://spec.graphql.org/October2021/#NegativeSign struct negative_sign : one<'-'> { }; -// http://spec.graphql.org/June2018/#IntegerPart +// https://spec.graphql.org/October2021/#IntegerPart struct integer_part : seq, sor>>> { }; -// http://spec.graphql.org/June2018/#IntValue +// https://spec.graphql.org/October2021/#IntValue struct integer_value : integer_part { }; @@ -198,17 +214,17 @@ struct fractional_part_content : plus { }; -// http://spec.graphql.org/June2018/#FractionalPart +// https://spec.graphql.org/October2021/#FractionalPart struct fractional_part : if_must, fractional_part_content> { }; -// http://spec.graphql.org/June2018/#ExponentIndicator +// https://spec.graphql.org/October2021/#ExponentIndicator struct exponent_indicator : one<'e', 'E'> { }; -// http://spec.graphql.org/June2018/#Sign +// https://spec.graphql.org/October2021/#Sign struct sign : one<'+', '-'> { }; @@ -217,12 +233,12 @@ struct exponent_part_content : seq, plus> { }; -// http://spec.graphql.org/June2018/#ExponentPart +// https://spec.graphql.org/October2021/#ExponentPart struct exponent_part : if_must { }; -// http://spec.graphql.org/June2018/#FloatValue +// https://spec.graphql.org/October2021/#FloatValue struct float_value : seq>> { @@ -236,17 +252,17 @@ struct false_keyword : TAO_PEGTL_KEYWORD("false") { }; -// http://spec.graphql.org/June2018/#BooleanValue +// https://spec.graphql.org/October2021/#BooleanValue struct bool_value : sor { }; -// http://spec.graphql.org/June2018/#EnumValue +// https://spec.graphql.org/October2021/#EnumValue struct enum_value : seq, name> { }; -// http://spec.graphql.org/June2018/#OperationType +// https://spec.graphql.org/October2021/#OperationType struct operation_type : sor @@ -257,7 +273,7 @@ struct alias_name : name { }; -// http://spec.graphql.org/June2018/#Alias +// https://spec.graphql.org/October2021/#Alias struct alias : seq, one<':'>> { }; @@ -272,7 +288,7 @@ struct argument_content : seq, one<':'>, star, input_valu { }; -// http://spec.graphql.org/June2018/#Argument +// https://spec.graphql.org/October2021/#Argument struct argument : if_must { }; @@ -282,7 +298,7 @@ struct arguments_content { }; -// http://spec.graphql.org/June2018/#Arguments +// https://spec.graphql.org/October2021/#Arguments struct arguments : if_must, arguments_content> { }; @@ -294,7 +310,7 @@ struct list_value_content { }; -// http://spec.graphql.org/June2018/#ListValue +// https://spec.graphql.org/October2021/#ListValue struct list_value : if_must, list_value_content> { }; @@ -307,7 +323,7 @@ struct object_field_content : seq, one<':'>, star, input_ { }; -// http://spec.graphql.org/June2018/#ObjectField +// https://spec.graphql.org/October2021/#ObjectField struct object_field : if_must { }; @@ -317,7 +333,7 @@ struct object_value_content { }; -// http://spec.graphql.org/June2018/#ObjectValue +// https://spec.graphql.org/October2021/#ObjectValue struct object_value : if_must, object_value_content> { }; @@ -332,7 +348,7 @@ struct input_value_content { }; -// http://spec.graphql.org/June2018/#Value +// https://spec.graphql.org/October2021/#Value struct input_value : must { }; @@ -345,12 +361,12 @@ struct default_value_content : seq, input_value> { }; -// http://spec.graphql.org/June2018/#DefaultValue +// https://spec.graphql.org/October2021/#DefaultValue struct default_value : if_must, default_value_content> { }; -// http://spec.graphql.org/June2018/#NamedType +// https://spec.graphql.org/October2021/#NamedType struct named_type : name { }; @@ -363,12 +379,12 @@ struct list_type_content { }; -// http://spec.graphql.org/June2018/#ListType +// https://spec.graphql.org/October2021/#ListType struct list_type : if_must, list_type_content> { }; -// http://spec.graphql.org/June2018/#NonNullType +// https://spec.graphql.org/October2021/#NonNullType struct nonnull_type : seq, star, one<'!'>> { }; @@ -377,7 +393,7 @@ struct type_name_content : sor { }; -// http://spec.graphql.org/June2018/#Type +// https://spec.graphql.org/October2021/#Type struct type_name : must { }; @@ -387,7 +403,7 @@ struct variable_content { }; -// http://spec.graphql.org/June2018/#VariableDefinition +// https://spec.graphql.org/October2021/#VariableDefinition struct variable : if_must { }; @@ -397,7 +413,7 @@ struct variable_definitions_content { }; -// http://spec.graphql.org/June2018/#VariableDefinitions +// https://spec.graphql.org/October2021/#VariableDefinitions struct variable_definitions : if_must, variable_definitions_content> { }; @@ -410,12 +426,12 @@ struct directive_content : seq, arguments>> { }; -// http://spec.graphql.org/June2018/#Directive +// https://spec.graphql.org/October2021/#Directive struct directive : if_must, directive_content> { }; -// http://spec.graphql.org/June2018/#Directives +// https://spec.graphql.org/October2021/#Directives struct directives : list> { }; @@ -448,7 +464,7 @@ struct field_content { }; -// http://spec.graphql.org/June2018/#Field +// https://spec.graphql.org/October2021/#Field struct field : if_must { }; @@ -457,7 +473,7 @@ struct on_keyword : TAO_PEGTL_KEYWORD("on") { }; -// http://spec.graphql.org/June2018/#FragmentName +// https://spec.graphql.org/October2021/#FragmentName struct fragment_name : seq, name> { }; @@ -466,7 +482,7 @@ struct fragment_token : ellipsis { }; -// http://spec.graphql.org/June2018/#FragmentSpread +// https://spec.graphql.org/October2021/#FragmentSpread struct fragment_spread : seq, fragment_name, opt, directives>> { }; @@ -475,12 +491,12 @@ struct type_condition_content : seq, named_type> { }; -// http://spec.graphql.org/June2018/#TypeCondition +// https://spec.graphql.org/October2021/#TypeCondition struct type_condition : if_must { }; -// http://spec.graphql.org/June2018/#InlineFragment +// https://spec.graphql.org/October2021/#InlineFragment struct inline_fragment : seq, type_condition>, opt, directives>, star, selection_set> @@ -496,7 +512,7 @@ struct fragement_spread_or_inline_fragment { }; -// http://spec.graphql.org/June2018/#Selection +// https://spec.graphql.org/October2021/#Selection struct selection : sor { }; @@ -506,7 +522,7 @@ struct selection_set_content { }; -// http://spec.graphql.org/June2018/#SelectionSet +// https://spec.graphql.org/October2021/#SelectionSet struct selection_set : if_must, selection_set_content> { }; @@ -521,7 +537,7 @@ struct operation_definition_operation_type_content { }; -// http://spec.graphql.org/June2018/#OperationDefinition +// https://spec.graphql.org/October2021/#OperationDefinition struct operation_definition : sor, selection_set> { @@ -533,16 +549,21 @@ struct fragment_definition_content { }; -// http://spec.graphql.org/June2018/#FragmentDefinition +// https://spec.graphql.org/October2021/#FragmentDefinition struct fragment_definition : if_must { }; -// http://spec.graphql.org/June2018/#ExecutableDefinition +// https://spec.graphql.org/October2021/#ExecutableDefinition struct executable_definition : sor { }; +// https://spec.graphql.org/October2021/#Description +struct description : string_value +{ +}; + struct schema_keyword : TAO_PEGTL_KEYWORD("schema") { }; @@ -551,19 +572,23 @@ struct root_operation_definition_content : seq, one<':'>, star { }; +struct schema_definition_start : seq>, schema_keyword> +{ +}; + struct schema_definition_content : seq, directives>, star, one<'{'>, star, list>, star, must>> { }; -// http://spec.graphql.org/June2018/#SchemaDefinition -struct schema_definition : if_must +// https://spec.graphql.org/October2021/#SchemaDefinition +struct schema_definition : if_must { }; @@ -571,11 +596,6 @@ struct scalar_keyword : TAO_PEGTL_KEYWORD("scalar") { }; -// http://spec.graphql.org/June2018/#Description -struct description : string_value -{ -}; - struct scalar_name : name { }; @@ -589,7 +609,7 @@ struct scalar_type_definition_content { }; -// http://spec.graphql.org/June2018/#ScalarTypeDefinition +// https://spec.graphql.org/October2021/#ScalarTypeDefinition struct scalar_type_definition : if_must { @@ -610,7 +630,7 @@ struct arguments_definition_content { }; -// http://spec.graphql.org/June2018/#ArgumentsDefinition +// https://spec.graphql.org/October2021/#ArgumentsDefinition struct arguments_definition : if_must { }; @@ -625,7 +645,7 @@ struct field_definition_content { }; -// http://spec.graphql.org/June2018/#FieldDefinition +// https://spec.graphql.org/October2021/#FieldDefinition struct field_definition : if_must { }; @@ -635,7 +655,7 @@ struct fields_definition_content { }; -// http://spec.graphql.org/June2018/#FieldsDefinition +// https://spec.graphql.org/October2021/#FieldsDefinition struct fields_definition : if_must, fields_definition_content> { }; @@ -650,7 +670,7 @@ struct implements_interfaces_content { }; -// http://spec.graphql.org/June2018/#ImplementsInterfaces +// https://spec.graphql.org/October2021/#ImplementsInterfaces struct implements_interfaces : if_must { @@ -689,7 +709,7 @@ struct object_type_definition_content { }; -// http://spec.graphql.org/June2018/#ObjectTypeDefinition +// https://spec.graphql.org/October2021/#ObjectTypeDefinition struct object_type_definition : if_must { @@ -711,7 +731,11 @@ struct interface_type_definition_interface_name : seq, interface_n { }; -struct interface_type_definition_directives : opt, directives> +struct interface_type_definition_implements_interfaces : opt, implements_interfaces> +{ +}; + +struct interface_type_definition_directives : seq, directives> { }; @@ -721,13 +745,17 @@ struct interface_type_definition_fields_definition : seq, fields_d struct interface_type_definition_content : seq, + interface_type_definition_fields_definition>, + seq, - interface_type_definition_directives>> + interface_type_definition_implements_interfaces>> { }; -// http://spec.graphql.org/June2018/#InterfaceTypeDefinition +// https://spec.graphql.org/October2021/#InterfaceTypeDefinition struct interface_type_definition : if_must { @@ -755,7 +783,7 @@ struct union_member_types_content { }; -// http://spec.graphql.org/June2018/#UnionMemberTypes +// https://spec.graphql.org/October2021/#UnionMemberTypes struct union_member_types : if_must { }; @@ -775,7 +803,7 @@ struct union_type_definition_content { }; -// http://spec.graphql.org/June2018/#UnionTypeDefinition +// https://spec.graphql.org/October2021/#UnionTypeDefinition struct union_type_definition : if_must { }; @@ -796,7 +824,7 @@ struct enum_value_definition_content : opt, directives> { }; -// http://spec.graphql.org/June2018/#EnumValueDefinition +// https://spec.graphql.org/October2021/#EnumValueDefinition struct enum_value_definition : if_must { }; @@ -810,7 +838,7 @@ struct enum_values_definition_content { }; -// http://spec.graphql.org/June2018/#EnumValuesDefinition +// https://spec.graphql.org/October2021/#EnumValuesDefinition struct enum_values_definition : if_must { @@ -839,7 +867,7 @@ struct enum_type_definition_content { }; -// http://spec.graphql.org/June2018/#EnumTypeDefinition +// https://spec.graphql.org/October2021/#EnumTypeDefinition struct enum_type_definition : if_must { }; @@ -871,7 +899,7 @@ struct input_field_definition_content { }; -// http://spec.graphql.org/June2018/#InputValueDefinition +// https://spec.graphql.org/October2021/#InputValueDefinition struct input_field_definition : if_must { @@ -886,7 +914,7 @@ struct input_fields_definition_content { }; -// http://spec.graphql.org/June2018/#InputFieldsDefinition +// https://spec.graphql.org/October2021/#InputFieldsDefinition struct input_fields_definition : if_must { @@ -916,20 +944,20 @@ struct input_object_type_definition_content { }; -// http://spec.graphql.org/June2018/#InputObjectTypeDefinition +// https://spec.graphql.org/October2021/#InputObjectTypeDefinition struct input_object_type_definition : if_must { }; -// http://spec.graphql.org/June2018/#TypeDefinition +// https://spec.graphql.org/October2021/#TypeDefinition struct type_definition : sor { }; -// http://spec.graphql.org/June2018/#ExecutableDirectiveLocation +// https://spec.graphql.org/October2021/#ExecutableDirectiveLocation struct executable_directive_location : sor { }; -// http://spec.graphql.org/June2018/#DirectiveLocations +// https://spec.graphql.org/October2021/#DirectiveLocations struct directive_locations : seq, star>, list, one<'|'>, star>>> @@ -965,18 +993,23 @@ struct directive_definition_start { }; +struct repeatable_keyword : TAO_PEGTL_KEYWORD("repeatable") +{ +}; + struct directive_definition_content : seq, one<'@'>, directive_name, opt, arguments_definition>, - plus, on_keyword, plus, directive_locations> + opt, repeatable_keyword>, plus, on_keyword, plus, + directive_locations> { }; -// http://spec.graphql.org/June2018/#DirectiveDefinition +// https://spec.graphql.org/October2021/#DirectiveDefinition struct directive_definition : if_must { }; -// http://spec.graphql.org/June2018/#TypeSystemDefinition +// https://spec.graphql.org/October2021/#TypeSystemDefinition struct type_system_definition : sor { }; @@ -985,7 +1018,7 @@ struct extend_keyword : TAO_PEGTL_KEYWORD("extend") { }; -// http://spec.graphql.org/June2018/#OperationTypeDefinition +// https://spec.graphql.org/October2021/#OperationTypeDefinition struct operation_type_definition : root_operation_definition { }; @@ -1006,7 +1039,7 @@ struct schema_extension_content { }; -// http://spec.graphql.org/June2018/#SchemaExtension +// https://spec.graphql.org/October2021/#SchemaExtension struct schema_extension : if_must { }; @@ -1019,7 +1052,7 @@ struct scalar_type_extension_content : seq, scalar_name, star { }; @@ -1050,7 +1083,7 @@ struct object_type_extension_content { }; -// http://spec.graphql.org/June2018/#ObjectTypeExtension +// https://spec.graphql.org/October2021/#ObjectTypeExtension struct object_type_extension : if_must { }; @@ -1059,13 +1092,30 @@ struct interface_type_extension_start : seq, inter { }; +struct interface_type_extension_implements_interfaces : seq, implements_interfaces> +{ +}; + +struct interface_type_extension_directives : seq, directives> +{ +}; + +struct interface_type_extension_fields_definition : seq, fields_definition> +{ +}; + struct interface_type_extension_content : seq, interface_name, star, - sor>, fields_definition>, directives>> + sor, + opt, + interface_type_extension_fields_definition>, + seq, + interface_type_extension_directives>, + interface_type_extension_implements_interfaces>> { }; -// http://spec.graphql.org/June2018/#InterfaceTypeExtension +// https://spec.graphql.org/October2021/#InterfaceTypeExtension struct interface_type_extension : if_must { @@ -1081,7 +1131,7 @@ struct union_type_extension_content { }; -// http://spec.graphql.org/June2018/#UnionTypeExtension +// https://spec.graphql.org/October2021/#UnionTypeExtension struct union_type_extension : if_must { }; @@ -1096,7 +1146,7 @@ struct enum_type_extension_content { }; -// http://spec.graphql.org/June2018/#EnumTypeExtension +// https://spec.graphql.org/October2021/#EnumTypeExtension struct enum_type_extension : if_must { }; @@ -1111,25 +1161,25 @@ struct input_object_type_extension_content { }; -// http://spec.graphql.org/June2018/#InputObjectTypeExtension +// https://spec.graphql.org/October2021/#InputObjectTypeExtension struct input_object_type_extension : if_must { }; -// http://spec.graphql.org/June2018/#TypeExtension +// https://spec.graphql.org/October2021/#TypeExtension struct type_extension : sor { }; -// http://spec.graphql.org/June2018/#TypeSystemExtension +// https://spec.graphql.org/October2021/#TypeSystemExtension struct type_system_extension : sor { }; -// http://spec.graphql.org/June2018/#Definition +// https://spec.graphql.org/October2021/#Definition struct mixed_definition : sor { }; @@ -1141,7 +1191,7 @@ struct mixed_document_content { }; -// http://spec.graphql.org/June2018/#Document +// https://spec.graphql.org/October2021/#Document struct mixed_document : must { }; @@ -1153,12 +1203,12 @@ struct executable_document_content { }; -// http://spec.graphql.org/June2018/#Document +// https://spec.graphql.org/October2021/#Document struct executable_document : must { }; -// http://spec.graphql.org/June2018/#Definition +// https://spec.graphql.org/October2021/#Definition struct schema_type_definition : sor { }; @@ -1170,7 +1220,7 @@ struct schema_document_content { }; -// http://spec.graphql.org/June2018/#Document +// https://spec.graphql.org/October2021/#Document struct schema_document : must { }; diff --git a/include/graphqlservice/internal/Introspection.h b/include/graphqlservice/internal/Introspection.h new file mode 100644 index 00000000..b2448e62 --- /dev/null +++ b/include/graphqlservice/internal/Introspection.h @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef INTROSPECTION_H +#define INTROSPECTION_H + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include "graphqlservice/internal/Schema.h" + +namespace graphql::introspection { + +class Schema; +class Directive; +class Type; +class Field; +class InputValue; +class EnumValue; + +class Schema +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit Schema(const std::shared_ptr& schema); + + // Accessors + GRAPHQLINTROSPECTION_EXPORT std::optional getDescription() const; + GRAPHQLINTROSPECTION_EXPORT std::vector> getTypes() const; + GRAPHQLINTROSPECTION_EXPORT std::shared_ptr getQueryType() const; + GRAPHQLINTROSPECTION_EXPORT std::shared_ptr getMutationType() const; + GRAPHQLINTROSPECTION_EXPORT std::shared_ptr getSubscriptionType() const; + GRAPHQLINTROSPECTION_EXPORT std::vector> getDirectives() + const; + +private: + const std::shared_ptr _schema; +}; + +class Type +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit Type(const std::shared_ptr& type); + + // Accessors + GRAPHQLINTROSPECTION_EXPORT TypeKind getKind() const; + GRAPHQLINTROSPECTION_EXPORT std::optional getName() const; + GRAPHQLINTROSPECTION_EXPORT std::optional getDescription() const; + GRAPHQLINTROSPECTION_EXPORT std::optional>> + getFields(std::optional&& includeDeprecatedArg) const; + GRAPHQLINTROSPECTION_EXPORT std::optional>> + getInterfaces() const; + GRAPHQLINTROSPECTION_EXPORT std::optional>> + getPossibleTypes() const; + GRAPHQLINTROSPECTION_EXPORT std::optional>> + getEnumValues(std::optional&& includeDeprecatedArg) const; + GRAPHQLINTROSPECTION_EXPORT std::optional>> + getInputFields() const; + GRAPHQLINTROSPECTION_EXPORT std::shared_ptr getOfType() const; + GRAPHQLINTROSPECTION_EXPORT std::optional getSpecifiedByURL() const; + +private: + const std::shared_ptr _type; +}; + +class Field +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit Field(const std::shared_ptr& field); + + // Accessors + GRAPHQLINTROSPECTION_EXPORT std::string getName() const; + GRAPHQLINTROSPECTION_EXPORT std::optional getDescription() const; + GRAPHQLINTROSPECTION_EXPORT std::vector> getArgs() const; + GRAPHQLINTROSPECTION_EXPORT std::shared_ptr getType() const; + GRAPHQLINTROSPECTION_EXPORT bool getIsDeprecated() const; + GRAPHQLINTROSPECTION_EXPORT std::optional getDeprecationReason() const; + +private: + const std::shared_ptr _field; +}; + +class InputValue +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit InputValue( + const std::shared_ptr& inputValue); + + // Accessors + GRAPHQLINTROSPECTION_EXPORT std::string getName() const; + GRAPHQLINTROSPECTION_EXPORT std::optional getDescription() const; + GRAPHQLINTROSPECTION_EXPORT std::shared_ptr getType() const; + GRAPHQLINTROSPECTION_EXPORT std::optional getDefaultValue() const; + +private: + const std::shared_ptr _inputValue; +}; + +class EnumValue +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit EnumValue( + const std::shared_ptr& enumValue); + + // Accessors + GRAPHQLINTROSPECTION_EXPORT std::string getName() const; + GRAPHQLINTROSPECTION_EXPORT std::optional getDescription() const; + GRAPHQLINTROSPECTION_EXPORT bool getIsDeprecated() const; + GRAPHQLINTROSPECTION_EXPORT std::optional getDeprecationReason() const; + +private: + const std::shared_ptr _enumValue; +}; + +class Directive +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit Directive( + const std::shared_ptr& directive); + + // Accessors + GRAPHQLINTROSPECTION_EXPORT std::string getName() const; + GRAPHQLINTROSPECTION_EXPORT std::optional getDescription() const; + GRAPHQLINTROSPECTION_EXPORT std::vector getLocations() const; + GRAPHQLINTROSPECTION_EXPORT std::vector> getArgs() const; + GRAPHQLINTROSPECTION_EXPORT bool getIsRepeatable() const; + +private: + const std::shared_ptr _directive; +}; + +} // namespace graphql::introspection + +#endif // INTROSPECTION_H diff --git a/include/graphqlservice/internal/Schema.h b/include/graphqlservice/internal/Schema.h index 4e26b694..3d7d12b3 100644 --- a/include/graphqlservice/internal/Schema.h +++ b/include/graphqlservice/internal/Schema.h @@ -37,7 +37,8 @@ class EnumValue; class Schema : public std::enable_shared_from_this { public: - GRAPHQLSERVICE_EXPORT explicit Schema(bool noIntrospection = false); + GRAPHQLSERVICE_EXPORT explicit Schema( + bool noIntrospection = false, std::string_view description = ""); GRAPHQLSERVICE_EXPORT void AddQueryType(std::shared_ptr query); GRAPHQLSERVICE_EXPORT void AddMutationType(std::shared_ptr mutation); @@ -51,6 +52,7 @@ class Schema : public std::enable_shared_from_this // Accessors GRAPHQLSERVICE_EXPORT bool supportsIntrospection() const noexcept; + GRAPHQLSERVICE_EXPORT std::string_view description() const noexcept; GRAPHQLSERVICE_EXPORT const std::vector< std::pair>>& types() const noexcept; @@ -63,6 +65,7 @@ class Schema : public std::enable_shared_from_this private: const bool _noIntrospection = false; + const std::string_view _description; std::shared_ptr _query; std::shared_ptr _mutation; @@ -98,6 +101,7 @@ class BaseType : public std::enable_shared_from_this GRAPHQLSERVICE_EXPORT virtual const std::vector>& inputFields() const noexcept; GRAPHQLSERVICE_EXPORT virtual const std::weak_ptr& ofType() const noexcept; + GRAPHQLSERVICE_EXPORT virtual std::string_view specifiedByURL() const noexcept; protected: BaseType(introspection::TypeKind kind, std::string_view description); @@ -118,13 +122,15 @@ class ScalarType : public BaseType explicit ScalarType(init&& params); GRAPHQLSERVICE_EXPORT static std::shared_ptr Make( - std::string_view name, std::string_view description); + std::string_view name, std::string_view description, std::string_view specifiedByURL); // Accessors GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept final; + GRAPHQLSERVICE_EXPORT std::string_view specifiedByURL() const noexcept final; private: const std::string_view _name; + const std::string_view _specifiedByURL; }; class ObjectType : public BaseType @@ -171,7 +177,9 @@ class InterfaceType : public BaseType GRAPHQLSERVICE_EXPORT static std::shared_ptr Make( std::string_view name, std::string_view description); - GRAPHQLSERVICE_EXPORT void AddPossibleType(std::weak_ptr possibleType); + GRAPHQLSERVICE_EXPORT void AddPossibleType(std::weak_ptr possibleType); + GRAPHQLSERVICE_EXPORT void AddInterfaces( + std::vector>&& interfaces); GRAPHQLSERVICE_EXPORT void AddFields(std::vector>&& fields); // Accessors @@ -180,10 +188,13 @@ class InterfaceType : public BaseType const noexcept final; GRAPHQLSERVICE_EXPORT const std::vector>& possibleTypes() const noexcept final; + GRAPHQLSERVICE_EXPORT const std::vector>& interfaces() + const noexcept final; private: const std::string_view _name; + std::vector> _interfaces; std::vector> _fields; std::vector> _possibleTypes; }; @@ -389,7 +400,7 @@ class Directive : public std::enable_shared_from_this GRAPHQLSERVICE_EXPORT static std::shared_ptr Make(std::string_view name, std::string_view description, std::vector&& locations, - std::vector>&& args = {}); + std::vector>&& args, bool isRepeatable); // Accessors GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept; @@ -398,12 +409,14 @@ class Directive : public std::enable_shared_from_this const noexcept; GRAPHQLSERVICE_EXPORT const std::vector>& args() const noexcept; + GRAPHQLSERVICE_EXPORT bool isRepeatable() const noexcept; private: const std::string_view _name; const std::string_view _description; const std::vector _locations; const std::vector> _args; + const bool _isRepeatable; }; } // namespace schema diff --git a/include/graphqlservice/internal/Version.h b/include/graphqlservice/internal/Version.h index 1c3b8993..c4ac8f96 100644 --- a/include/graphqlservice/internal/Version.h +++ b/include/graphqlservice/internal/Version.h @@ -10,10 +10,10 @@ namespace graphql::internal { -constexpr std::string_view FullVersion { "3.6.0" }; +constexpr std::string_view FullVersion { "4.0.0" }; -constexpr size_t MajorVersion = 3; -constexpr size_t MinorVersion = 6; +constexpr size_t MajorVersion = 4; +constexpr size_t MinorVersion = 0; constexpr size_t PatchVersion = 0; } // namespace graphql::internal diff --git a/include/graphqlservice/introspection/DirectiveObject.h b/include/graphqlservice/introspection/DirectiveObject.h new file mode 100644 index 00000000..22b77759 --- /dev/null +++ b/include/graphqlservice/introspection/DirectiveObject.h @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef DIRECTIVEOBJECT_H +#define DIRECTIVEOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class Directive + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveLocations(service::ResolverParams&& params) const; + service::AwaitableResolver resolveArgs(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIsRepeatable(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar getName() const = 0; + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableScalar> getLocations() const = 0; + virtual service::AwaitableObject>> getArgs() const = 0; + virtual service::AwaitableScalar getIsRepeatable() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName() const final + { + return { _pimpl->getName() }; + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableScalar> getLocations() const final + { + return { _pimpl->getLocations() }; + } + + service::AwaitableObject>> getArgs() const final + { + return { _pimpl->getArgs() }; + } + + service::AwaitableScalar getIsRepeatable() const final + { + return { _pimpl->getIsRepeatable() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT Directive(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~Directive(); +}; + +} // namespace graphql::introspection::object + +#endif // DIRECTIVEOBJECT_H diff --git a/include/graphqlservice/introspection/EnumValueObject.h b/include/graphqlservice/introspection/EnumValueObject.h new file mode 100644 index 00000000..390565c7 --- /dev/null +++ b/include/graphqlservice/introspection/EnumValueObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef ENUMVALUEOBJECT_H +#define ENUMVALUEOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class EnumValue + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIsDeprecated(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDeprecationReason(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar getName() const = 0; + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableScalar getIsDeprecated() const = 0; + virtual service::AwaitableScalar> getDeprecationReason() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName() const final + { + return { _pimpl->getName() }; + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableScalar getIsDeprecated() const final + { + return { _pimpl->getIsDeprecated() }; + } + + service::AwaitableScalar> getDeprecationReason() const final + { + return { _pimpl->getDeprecationReason() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT EnumValue(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~EnumValue(); +}; + +} // namespace graphql::introspection::object + +#endif // ENUMVALUEOBJECT_H diff --git a/include/graphqlservice/introspection/FieldObject.h b/include/graphqlservice/introspection/FieldObject.h new file mode 100644 index 00000000..778286e0 --- /dev/null +++ b/include/graphqlservice/introspection/FieldObject.h @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef FIELDOBJECT_H +#define FIELDOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class Field + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveArgs(service::ResolverParams&& params) const; + service::AwaitableResolver resolveType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIsDeprecated(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDeprecationReason(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar getName() const = 0; + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableObject>> getArgs() const = 0; + virtual service::AwaitableObject> getType() const = 0; + virtual service::AwaitableScalar getIsDeprecated() const = 0; + virtual service::AwaitableScalar> getDeprecationReason() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName() const final + { + return { _pimpl->getName() }; + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableObject>> getArgs() const final + { + return { _pimpl->getArgs() }; + } + + service::AwaitableObject> getType() const final + { + return { _pimpl->getType() }; + } + + service::AwaitableScalar getIsDeprecated() const final + { + return { _pimpl->getIsDeprecated() }; + } + + service::AwaitableScalar> getDeprecationReason() const final + { + return { _pimpl->getDeprecationReason() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT Field(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~Field(); +}; + +} // namespace graphql::introspection::object + +#endif // FIELDOBJECT_H diff --git a/include/graphqlservice/introspection/InputValueObject.h b/include/graphqlservice/introspection/InputValueObject.h new file mode 100644 index 00000000..1b9ed622 --- /dev/null +++ b/include/graphqlservice/introspection/InputValueObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef INPUTVALUEOBJECT_H +#define INPUTVALUEOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class InputValue + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDefaultValue(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar getName() const = 0; + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableObject> getType() const = 0; + virtual service::AwaitableScalar> getDefaultValue() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName() const final + { + return { _pimpl->getName() }; + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableObject> getType() const final + { + return { _pimpl->getType() }; + } + + service::AwaitableScalar> getDefaultValue() const final + { + return { _pimpl->getDefaultValue() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT InputValue(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~InputValue(); +}; + +} // namespace graphql::introspection::object + +#endif // INPUTVALUEOBJECT_H diff --git a/include/graphqlservice/introspection/Introspection.h b/include/graphqlservice/introspection/Introspection.h deleted file mode 100644 index d0352a7a..00000000 --- a/include/graphqlservice/introspection/Introspection.h +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#ifndef INTROSPECTION_H -#define INTROSPECTION_H - -#include "graphqlservice/internal/Schema.h" - -#include "graphqlservice/introspection/IntrospectionSchema.h" - -namespace graphql::introspection { - -class Schema; -class Directive; -class Type; -class Field; -class InputValue; -class EnumValue; - -class Schema : public object::Schema -{ -public: - GRAPHQLINTROSPECTION_EXPORT explicit Schema(const std::shared_ptr& schema); - - // Accessors - service::FieldResult>> getTypes( - service::FieldParams&& params) const override; - service::FieldResult> getQueryType( - service::FieldParams&& params) const override; - service::FieldResult> getMutationType( - service::FieldParams&& params) const override; - service::FieldResult> getSubscriptionType( - service::FieldParams&& params) const override; - service::FieldResult>> getDirectives( - service::FieldParams&& params) const override; - -private: - const std::shared_ptr _schema; -}; - -class Type : public object::Type -{ -public: - GRAPHQLINTROSPECTION_EXPORT explicit Type(const std::shared_ptr& type); - - // Accessors - service::FieldResult getKind(service::FieldParams&&) const override; - service::FieldResult> getName( - service::FieldParams&& params) const override; - service::FieldResult> getDescription( - service::FieldParams&& params) const override; - service::FieldResult>>> getFields( - service::FieldParams&& params, - std::optional&& includeDeprecatedArg) const override; - service::FieldResult>>> getInterfaces( - service::FieldParams&& params) const override; - service::FieldResult>>> - getPossibleTypes(service::FieldParams&& params) const override; - service::FieldResult>>> - getEnumValues(service::FieldParams&& params, - std::optional&& includeDeprecatedArg) const override; - service::FieldResult>>> - getInputFields(service::FieldParams&& params) const override; - service::FieldResult> getOfType( - service::FieldParams&& params) const override; - -private: - const std::shared_ptr _type; -}; - -class Field : public object::Field -{ -public: - GRAPHQLINTROSPECTION_EXPORT explicit Field(const std::shared_ptr& field); - - // Accessors - service::FieldResult getName( - service::FieldParams&& params) const override; - service::FieldResult> getDescription( - service::FieldParams&& params) const override; - service::FieldResult>> getArgs( - service::FieldParams&& params) const override; - service::FieldResult> getType( - service::FieldParams&& params) const override; - service::FieldResult getIsDeprecated( - service::FieldParams&& params) const override; - service::FieldResult> getDeprecationReason( - service::FieldParams&& params) const override; - -private: - const std::shared_ptr _field; -}; - -class InputValue : public object::InputValue -{ -public: - GRAPHQLINTROSPECTION_EXPORT explicit InputValue( - const std::shared_ptr& inputValue); - - // Accessors - service::FieldResult getName( - service::FieldParams&& params) const override; - service::FieldResult> getDescription( - service::FieldParams&& params) const override; - service::FieldResult> getType( - service::FieldParams&& params) const override; - service::FieldResult> getDefaultValue( - service::FieldParams&& params) const override; - -private: - const std::shared_ptr _inputValue; -}; - -class EnumValue : public object::EnumValue -{ -public: - GRAPHQLINTROSPECTION_EXPORT explicit EnumValue( - const std::shared_ptr& enumValue); - - // Accessors - service::FieldResult getName( - service::FieldParams&& params) const override; - service::FieldResult> getDescription( - service::FieldParams&& params) const override; - service::FieldResult getIsDeprecated( - service::FieldParams&& params) const override; - service::FieldResult> getDeprecationReason( - service::FieldParams&& params) const override; - -private: - const std::shared_ptr _enumValue; -}; - -class Directive : public object::Directive -{ -public: - GRAPHQLINTROSPECTION_EXPORT explicit Directive( - const std::shared_ptr& directive); - - // Accessors - service::FieldResult getName( - service::FieldParams&& params) const override; - service::FieldResult> getDescription( - service::FieldParams&& params) const override; - service::FieldResult> getLocations( - service::FieldParams&& params) const override; - service::FieldResult>> getArgs( - service::FieldParams&& params) const override; - -private: - const std::shared_ptr _directive; -}; - -} // namespace graphql::introspection - -#endif // INTROSPECTION_H diff --git a/include/graphqlservice/introspection/IntrospectionSchema.h b/include/graphqlservice/introspection/IntrospectionSchema.h index 6eaf1eb6..9507b218 100644 --- a/include/graphqlservice/introspection/IntrospectionSchema.h +++ b/include/graphqlservice/introspection/IntrospectionSchema.h @@ -10,9 +10,9 @@ #include "graphqlservice/internal/Schema.h" -// Check if the library version is compatible with schemagen 3.6.0 -static_assert(graphql::internal::MajorVersion == 3, "regenerate with schemagen: major version mismatch"); -static_assert(graphql::internal::MinorVersion == 6, "regenerate with schemagen: minor version mismatch"); +// Check if the library version is compatible with schemagen 4.0.0 +static_assert(graphql::internal::MajorVersion == 4, "regenerate with schemagen: major version mismatch"); +static_assert(graphql::internal::MinorVersion == 0, "regenerate with schemagen: minor version mismatch"); // clang-format off #ifdef GRAPHQL_DLLEXPORTS @@ -54,6 +54,7 @@ enum class DirectiveLocation FRAGMENT_DEFINITION, FRAGMENT_SPREAD, INLINE_FRAGMENT, + VARIABLE_DEFINITION, SCHEMA, SCALAR, OBJECT, @@ -67,8 +68,6 @@ enum class DirectiveLocation INPUT_FIELD_DEFINITION }; -namespace object { - class Schema; class Type; class Field; @@ -76,150 +75,24 @@ class InputValue; class EnumValue; class Directive; -class Schema - : public service::Object -{ -protected: - explicit Schema(); - -public: - virtual service::FieldResult>> getTypes(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getQueryType(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getMutationType(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getSubscriptionType(service::FieldParams&& params) const = 0; - virtual service::FieldResult>> getDirectives(service::FieldParams&& params) const = 0; - -private: - std::future resolveTypes(service::ResolverParams&& params); - std::future resolveQueryType(service::ResolverParams&& params); - std::future resolveMutationType(service::ResolverParams&& params); - std::future resolveSubscriptionType(service::ResolverParams&& params); - std::future resolveDirectives(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Type - : public service::Object -{ -protected: - explicit Type(); - -public: - virtual service::FieldResult getKind(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getName(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getDescription(service::FieldParams&& params) const = 0; - virtual service::FieldResult>>> getFields(service::FieldParams&& params, std::optional&& includeDeprecatedArg) const = 0; - virtual service::FieldResult>>> getInterfaces(service::FieldParams&& params) const = 0; - virtual service::FieldResult>>> getPossibleTypes(service::FieldParams&& params) const = 0; - virtual service::FieldResult>>> getEnumValues(service::FieldParams&& params, std::optional&& includeDeprecatedArg) const = 0; - virtual service::FieldResult>>> getInputFields(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getOfType(service::FieldParams&& params) const = 0; - -private: - std::future resolveKind(service::ResolverParams&& params); - std::future resolveName(service::ResolverParams&& params); - std::future resolveDescription(service::ResolverParams&& params); - std::future resolveFields(service::ResolverParams&& params); - std::future resolveInterfaces(service::ResolverParams&& params); - std::future resolvePossibleTypes(service::ResolverParams&& params); - std::future resolveEnumValues(service::ResolverParams&& params); - std::future resolveInputFields(service::ResolverParams&& params); - std::future resolveOfType(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Field - : public service::Object -{ -protected: - explicit Field(); - -public: - virtual service::FieldResult getName(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getDescription(service::FieldParams&& params) const = 0; - virtual service::FieldResult>> getArgs(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getType(service::FieldParams&& params) const = 0; - virtual service::FieldResult getIsDeprecated(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getDeprecationReason(service::FieldParams&& params) const = 0; - -private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveDescription(service::ResolverParams&& params); - std::future resolveArgs(service::ResolverParams&& params); - std::future resolveType(service::ResolverParams&& params); - std::future resolveIsDeprecated(service::ResolverParams&& params); - std::future resolveDeprecationReason(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class InputValue - : public service::Object -{ -protected: - explicit InputValue(); - -public: - virtual service::FieldResult getName(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getDescription(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getType(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getDefaultValue(service::FieldParams&& params) const = 0; - -private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveDescription(service::ResolverParams&& params); - std::future resolveType(service::ResolverParams&& params); - std::future resolveDefaultValue(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class EnumValue - : public service::Object -{ -protected: - explicit EnumValue(); - -public: - virtual service::FieldResult getName(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getDescription(service::FieldParams&& params) const = 0; - virtual service::FieldResult getIsDeprecated(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getDeprecationReason(service::FieldParams&& params) const = 0; - -private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveDescription(service::ResolverParams&& params); - std::future resolveIsDeprecated(service::ResolverParams&& params); - std::future resolveDeprecationReason(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; +namespace object { -class Directive - : public service::Object -{ -protected: - explicit Directive(); - -public: - virtual service::FieldResult getName(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getDescription(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getLocations(service::FieldParams&& params) const = 0; - virtual service::FieldResult>> getArgs(service::FieldParams&& params) const = 0; - -private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveDescription(service::ResolverParams&& params); - std::future resolveLocations(service::ResolverParams&& params); - std::future resolveArgs(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; +class Schema; +class Type; +class Field; +class InputValue; +class EnumValue; +class Directive; } // namespace object +void AddSchemaDetails(const std::shared_ptr& typeSchema, const std::shared_ptr& schema); +void AddTypeDetails(const std::shared_ptr& typeType, const std::shared_ptr& schema); +void AddFieldDetails(const std::shared_ptr& typeField, const std::shared_ptr& schema); +void AddInputValueDetails(const std::shared_ptr& typeInputValue, const std::shared_ptr& schema); +void AddEnumValueDetails(const std::shared_ptr& typeEnumValue, const std::shared_ptr& schema); +void AddDirectiveDetails(const std::shared_ptr& typeDirective, const std::shared_ptr& schema); + GRAPHQLINTROSPECTION_EXPORT void AddTypesToSchema(const std::shared_ptr& schema); } // namespace introspection @@ -232,14 +105,20 @@ template <> GRAPHQLINTROSPECTION_EXPORT introspection::TypeKind ModifiedArgument::convert( const response::Value& value); template <> -GRAPHQLINTROSPECTION_EXPORT std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params); +GRAPHQLINTROSPECTION_EXPORT AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params); +template <> +GRAPHQLINTROSPECTION_EXPORT void ModifiedResult::validateScalar( + const response::Value& value); template <> GRAPHQLINTROSPECTION_EXPORT introspection::DirectiveLocation ModifiedArgument::convert( const response::Value& value); template <> -GRAPHQLINTROSPECTION_EXPORT std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params); +GRAPHQLINTROSPECTION_EXPORT AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params); +template <> +GRAPHQLINTROSPECTION_EXPORT void ModifiedResult::validateScalar( + const response::Value& value); #endif // GRAPHQL_DLLEXPORTS } // namespace service diff --git a/include/graphqlservice/introspection/SchemaObject.h b/include/graphqlservice/introspection/SchemaObject.h new file mode 100644 index 00000000..a8f05373 --- /dev/null +++ b/include/graphqlservice/introspection/SchemaObject.h @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef SCHEMAOBJECT_H +#define SCHEMAOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class Schema + : public service::Object +{ +private: + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveTypes(service::ResolverParams&& params) const; + service::AwaitableResolver resolveQueryType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveMutationType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveSubscriptionType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDirectives(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableObject>> getTypes() const = 0; + virtual service::AwaitableObject> getQueryType() const = 0; + virtual service::AwaitableObject> getMutationType() const = 0; + virtual service::AwaitableObject> getSubscriptionType() const = 0; + virtual service::AwaitableObject>> getDirectives() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableObject>> getTypes() const final + { + return { _pimpl->getTypes() }; + } + + service::AwaitableObject> getQueryType() const final + { + return { _pimpl->getQueryType() }; + } + + service::AwaitableObject> getMutationType() const final + { + return { _pimpl->getMutationType() }; + } + + service::AwaitableObject> getSubscriptionType() const final + { + return { _pimpl->getSubscriptionType() }; + } + + service::AwaitableObject>> getDirectives() const final + { + return { _pimpl->getDirectives() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT Schema(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~Schema(); +}; + +} // namespace graphql::introspection::object + +#endif // SCHEMAOBJECT_H diff --git a/include/graphqlservice/introspection/TypeObject.h b/include/graphqlservice/introspection/TypeObject.h new file mode 100644 index 00000000..32bc9bdb --- /dev/null +++ b/include/graphqlservice/introspection/TypeObject.h @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef TYPEOBJECT_H +#define TYPEOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class Type + : public service::Object +{ +private: + service::AwaitableResolver resolveKind(service::ResolverParams&& params) const; + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveFields(service::ResolverParams&& params) const; + service::AwaitableResolver resolveInterfaces(service::ResolverParams&& params) const; + service::AwaitableResolver resolvePossibleTypes(service::ResolverParams&& params) const; + service::AwaitableResolver resolveEnumValues(service::ResolverParams&& params) const; + service::AwaitableResolver resolveInputFields(service::ResolverParams&& params) const; + service::AwaitableResolver resolveOfType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveSpecifiedByURL(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar getKind() const = 0; + virtual service::AwaitableScalar> getName() const = 0; + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableObject>>> getFields(std::optional&& includeDeprecatedArg) const = 0; + virtual service::AwaitableObject>>> getInterfaces() const = 0; + virtual service::AwaitableObject>>> getPossibleTypes() const = 0; + virtual service::AwaitableObject>>> getEnumValues(std::optional&& includeDeprecatedArg) const = 0; + virtual service::AwaitableObject>>> getInputFields() const = 0; + virtual service::AwaitableObject> getOfType() const = 0; + virtual service::AwaitableScalar> getSpecifiedByURL() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getKind() const final + { + return { _pimpl->getKind() }; + } + + service::AwaitableScalar> getName() const final + { + return { _pimpl->getName() }; + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableObject>>> getFields(std::optional&& includeDeprecatedArg) const final + { + return { _pimpl->getFields(std::move(includeDeprecatedArg)) }; + } + + service::AwaitableObject>>> getInterfaces() const final + { + return { _pimpl->getInterfaces() }; + } + + service::AwaitableObject>>> getPossibleTypes() const final + { + return { _pimpl->getPossibleTypes() }; + } + + service::AwaitableObject>>> getEnumValues(std::optional&& includeDeprecatedArg) const final + { + return { _pimpl->getEnumValues(std::move(includeDeprecatedArg)) }; + } + + service::AwaitableObject>>> getInputFields() const final + { + return { _pimpl->getInputFields() }; + } + + service::AwaitableObject> getOfType() const final + { + return { _pimpl->getOfType() }; + } + + service::AwaitableScalar> getSpecifiedByURL() const final + { + return { _pimpl->getSpecifiedByURL() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT Type(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~Type(); +}; + +} // namespace graphql::introspection::object + +#endif // TYPEOBJECT_H diff --git a/res/ClientGen.rc b/res/ClientGen.rc index 61b529c6..f291dfb8 100644 --- a/res/ClientGen.rc +++ b/res/ClientGen.rc @@ -3,8 +3,8 @@ #include -#define CLIENTGEN_RC_VERSION 3,6,0,0 -#define CLIENTGEN_RC_VERSION_STR "3.6.0" +#define CLIENTGEN_RC_VERSION 4,0,0,0 +#define CLIENTGEN_RC_VERSION_STR "4.0.0" #ifndef DEBUG #define VER_DEBUG 0 diff --git a/res/SchemaGen.rc b/res/SchemaGen.rc index de39f745..9ad9eea0 100644 --- a/res/SchemaGen.rc +++ b/res/SchemaGen.rc @@ -3,8 +3,8 @@ #include -#define SCHEMAGEN_RC_VERSION 3,6,0,0 -#define SCHEMAGEN_RC_VERSION_STR "3.6.0" +#define SCHEMAGEN_RC_VERSION 4,0,0,0 +#define SCHEMAGEN_RC_VERSION_STR "4.0.0" #ifndef DEBUG #define VER_DEBUG 0 diff --git a/res/graphqlclient_version.rc b/res/graphqlclient_version.rc index 1aa12516..135ce4ad 100644 --- a/res/graphqlclient_version.rc +++ b/res/graphqlclient_version.rc @@ -3,8 +3,8 @@ #include -#define GRAPHQL_RC_VERSION 3,6,0,0 -#define GRAPHQL_RC_VERSION_STR "3.6.0" +#define GRAPHQL_RC_VERSION 4,0,0,0 +#define GRAPHQL_RC_VERSION_STR "4.0.0" #ifndef DEBUG #define VER_DEBUG 0 diff --git a/res/graphqlintrospection_version.rc b/res/graphqlintrospection_version.rc index 2638d8fe..3ac6cbc2 100644 --- a/res/graphqlintrospection_version.rc +++ b/res/graphqlintrospection_version.rc @@ -3,8 +3,8 @@ #include -#define GRAPHQL_RC_VERSION 3,6,0,0 -#define GRAPHQL_RC_VERSION_STR "3.6.0" +#define GRAPHQL_RC_VERSION 4,0,0,0 +#define GRAPHQL_RC_VERSION_STR "4.0.0" #ifndef DEBUG #define VER_DEBUG 0 diff --git a/res/graphqljson_version.rc b/res/graphqljson_version.rc index b3d82a4c..7f07d762 100644 --- a/res/graphqljson_version.rc +++ b/res/graphqljson_version.rc @@ -3,8 +3,8 @@ #include -#define GRAPHQL_RC_VERSION 3,6,0,0 -#define GRAPHQL_RC_VERSION_STR "3.6.0" +#define GRAPHQL_RC_VERSION 4,0,0,0 +#define GRAPHQL_RC_VERSION_STR "4.0.0" #ifndef DEBUG #define VER_DEBUG 0 diff --git a/res/graphqlpeg_version.rc b/res/graphqlpeg_version.rc index f4f730cd..8de47acc 100644 --- a/res/graphqlpeg_version.rc +++ b/res/graphqlpeg_version.rc @@ -3,8 +3,8 @@ #include -#define GRAPHQL_RC_VERSION 3,6,0,0 -#define GRAPHQL_RC_VERSION_STR "3.6.0" +#define GRAPHQL_RC_VERSION 4,0,0,0 +#define GRAPHQL_RC_VERSION_STR "4.0.0" #ifndef DEBUG #define VER_DEBUG 0 diff --git a/res/graphqlresponse_version.rc b/res/graphqlresponse_version.rc index f7bf80e6..d2dd6df0 100644 --- a/res/graphqlresponse_version.rc +++ b/res/graphqlresponse_version.rc @@ -3,8 +3,8 @@ #include -#define GRAPHQL_RC_VERSION 3,6,0,0 -#define GRAPHQL_RC_VERSION_STR "3.6.0" +#define GRAPHQL_RC_VERSION 4,0,0,0 +#define GRAPHQL_RC_VERSION_STR "4.0.0" #ifndef DEBUG #define VER_DEBUG 0 diff --git a/res/graphqlservice_version.rc b/res/graphqlservice_version.rc index 462e91ae..da4609f0 100644 --- a/res/graphqlservice_version.rc +++ b/res/graphqlservice_version.rc @@ -3,8 +3,8 @@ #include -#define GRAPHQL_RC_VERSION 3,6,0,0 -#define GRAPHQL_RC_VERSION_STR "3.6.0" +#define GRAPHQL_RC_VERSION 4,0,0,0 +#define GRAPHQL_RC_VERSION_STR "4.0.0" #ifndef DEBUG #define VER_DEBUG 0 diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 64e3d512..45c1691b 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -1,432 +1,9 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -cmake_minimum_required(VERSION 3.8.2) +cmake_minimum_required(VERSION 3.15) -if(GRAPHQL_UPDATE_SAMPLES) - # unifiedschema - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/unified) - - add_custom_command( - OUTPUT - ${CMAKE_CURRENT_BINARY_DIR}/unified/TodaySchema.cpp - ${CMAKE_CURRENT_BINARY_DIR}/unified/TodaySchema.h - COMMAND schemagen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.today.graphql" --prefix="Today" --namespace="today" - COMMAND ${CMAKE_COMMAND} -E copy_if_different - TodaySchema.cpp - TodaySchema.h - ${CMAKE_CURRENT_SOURCE_DIR}/unified - DEPENDS schemagen graphqlpeg schema.today.graphql - WORKING_DIRECTORY unified - COMMENT "Generating mock TodaySchema files") - - # unifiedschema_nointrospection - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/unified_nointrospection) - - add_custom_command( - OUTPUT - ${CMAKE_CURRENT_BINARY_DIR}/unified_nointrospection/TodaySchema.cpp - ${CMAKE_CURRENT_BINARY_DIR}/unified_nointrospection/TodaySchema.h - COMMAND schemagen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.today.graphql" --prefix="Today" --namespace="today" --no-introspection - COMMAND ${CMAKE_COMMAND} -E copy_if_different - TodaySchema.cpp - TodaySchema.h - ${CMAKE_CURRENT_SOURCE_DIR}/unified_nointrospection - DEPENDS schemagen graphqlpeg schema.today.graphql - WORKING_DIRECTORY unified_nointrospection - COMMENT "Generating mock TodaySchema files without Introspection (--no-introspection)") - - # validationschema - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/validation) - - add_custom_command( - OUTPUT - ${CMAKE_CURRENT_BINARY_DIR}/validation/ValidationSchema.cpp - ${CMAKE_CURRENT_BINARY_DIR}/validation/ValidationSchema.h - COMMAND schemagen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.validation.graphql" --prefix="Validation" --namespace="validation" - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ValidationSchema.cpp - ValidationSchema.h - ${CMAKE_CURRENT_SOURCE_DIR}/validation - DEPENDS schemagen graphqlpeg schema.validation.graphql - WORKING_DIRECTORY validation - COMMENT "Generating ValidationSchema files") - - # separateschema - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/separate) - - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/separate/today_schema_files - COMMAND schemagen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.today.graphql" --prefix="Today" --namespace="today" --separate-files > today_schema_files - COMMAND ${CMAKE_COMMAND} -E copy_if_different today_schema_files ${CMAKE_CURRENT_SOURCE_DIR}/separate - DEPENDS schemagen graphqlpeg schema.today.graphql - WORKING_DIRECTORY separate - COMMENT "Generating mock TodaySchema (--separate-files)") - - # separateschema_nointrospection - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/separate_nointrospection) - - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/separate_nointrospection/today_schema_files - COMMAND schemagen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.today.graphql" --prefix="Today" --namespace="today" --no-introspection --separate-files > today_schema_files - COMMAND ${CMAKE_COMMAND} -E copy_if_different today_schema_files ${CMAKE_CURRENT_SOURCE_DIR}/separate_nointrospection - DEPENDS schemagen graphqlpeg schema.today.graphql - WORKING_DIRECTORY separate_nointrospection - COMMENT "Generating mock TodaySchema without Introspection (--no-introspection --separate-files)") - - # learn - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/learn) - - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/learn/learn_schema_files - COMMAND schemagen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.learn.graphql" --prefix="StarWars" --namespace="learn" --separate-files > learn_schema_files - COMMAND ${CMAKE_COMMAND} -E copy_if_different learn_schema_files ${CMAKE_CURRENT_SOURCE_DIR}/learn - DEPENDS schemagen graphqlpeg schema.learn.graphql - WORKING_DIRECTORY learn - COMMENT "Generating mock StarWarsSchema (--separate-files)") - - add_custom_command( - OUTPUT updated_samples - COMMAND ${CMAKE_COMMAND} - "-DSCHEMA_SOURCE_LIST=today_schema_files" - "-DSCHEMA_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/separate" - "-DSCHEMA_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/separate" - -P "${CMAKE_CURRENT_SOURCE_DIR}/update_samples.cmake" - COMMAND ${CMAKE_COMMAND} - "-DSCHEMA_SOURCE_LIST=today_schema_files" - "-DSCHEMA_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/separate_nointrospection" - "-DSCHEMA_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/separate_nointrospection" - -P "${CMAKE_CURRENT_SOURCE_DIR}/update_samples.cmake" - COMMAND ${CMAKE_COMMAND} - "-DSCHEMA_SOURCE_LIST=learn_schema_files" - "-DSCHEMA_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/learn" - "-DSCHEMA_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/learn" - -P "${CMAKE_CURRENT_SOURCE_DIR}/update_samples.cmake" - COMMAND ${CMAKE_COMMAND} -E touch updated_samples - DEPENDS - ${CMAKE_CURRENT_BINARY_DIR}/separate/today_schema_files - ${CMAKE_CURRENT_BINARY_DIR}/separate_nointrospection/today_schema_files - ${CMAKE_CURRENT_BINARY_DIR}/learn/learn_schema_files - COMMENT "Updating sample files") - - add_custom_target(update_samples ALL - DEPENDS - ${CMAKE_CURRENT_BINARY_DIR}/unified/TodaySchema.cpp - ${CMAKE_CURRENT_BINARY_DIR}/unified/TodaySchema.h - ${CMAKE_CURRENT_BINARY_DIR}/unified_nointrospection/TodaySchema.cpp - ${CMAKE_CURRENT_BINARY_DIR}/unified_nointrospection/TodaySchema.h - ${CMAKE_CURRENT_BINARY_DIR}/validation/ValidationSchema.cpp - ${CMAKE_CURRENT_BINARY_DIR}/validation/ValidationSchema.h - updated_samples) - - if(GRAPHQL_BUILD_CLIENTGEN) - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/client) - - # query.today.graphql - add_custom_command( - OUTPUT - ${CMAKE_CURRENT_BINARY_DIR}/client/QueryClient.cpp - ${CMAKE_CURRENT_BINARY_DIR}/client/QueryClient.h - COMMAND clientgen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.today.graphql" --request="${CMAKE_CURRENT_SOURCE_DIR}/query.today.graphql" --prefix="Query" --namespace="query" - COMMAND ${CMAKE_COMMAND} -E copy_if_different - QueryClient.cpp - QueryClient.h - ${CMAKE_CURRENT_SOURCE_DIR}/client - DEPENDS clientgen schema.today.graphql query.today.graphql - WORKING_DIRECTORY client - COMMENT "Generating QueryClient samples") - - # mutate.today.graphql - add_custom_command( - OUTPUT - ${CMAKE_CURRENT_BINARY_DIR}/client/MutateClient.cpp - ${CMAKE_CURRENT_BINARY_DIR}/client/MutateClient.h - COMMAND clientgen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.today.graphql" --request="${CMAKE_CURRENT_SOURCE_DIR}/mutate.today.graphql" --prefix="Mutate" --namespace="mutate" - COMMAND ${CMAKE_COMMAND} -E copy_if_different - MutateClient.cpp - MutateClient.h - ${CMAKE_CURRENT_SOURCE_DIR}/client - DEPENDS clientgen schema.today.graphql mutate.today.graphql - WORKING_DIRECTORY client - COMMENT "Generating MutateClient samples") - - # subscribe.today.graphql - add_custom_command( - OUTPUT - ${CMAKE_CURRENT_BINARY_DIR}/client/SubscribeClient.cpp - ${CMAKE_CURRENT_BINARY_DIR}/client/SubscribeClient.h - COMMAND clientgen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.today.graphql" --request="${CMAKE_CURRENT_SOURCE_DIR}/subscribe.today.graphql" --prefix="Subscribe" --namespace="subscribe" - COMMAND ${CMAKE_COMMAND} -E copy_if_different - SubscribeClient.cpp - SubscribeClient.h - ${CMAKE_CURRENT_SOURCE_DIR}/client - DEPENDS clientgen schema.today.graphql subscribe.today.graphql - WORKING_DIRECTORY client - COMMENT "Generating SubscribeClient samples") - - # client.benchmark.today.graphql - add_custom_command( - OUTPUT - ${CMAKE_CURRENT_BINARY_DIR}/client/BenchmarkClient.cpp - ${CMAKE_CURRENT_BINARY_DIR}/client/BenchmarkClient.h - COMMAND clientgen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.today.graphql" --request="${CMAKE_CURRENT_SOURCE_DIR}/client.benchmark.today.graphql" --prefix="Benchmark" --namespace="benchmark" - COMMAND ${CMAKE_COMMAND} -E copy_if_different - BenchmarkClient.cpp - BenchmarkClient.h - ${CMAKE_CURRENT_SOURCE_DIR}/client - DEPENDS clientgen schema.today.graphql client.benchmark.today.graphql - WORKING_DIRECTORY client - COMMENT "Generating BenchmarkClient samples") - - add_custom_target(update_client_samples ALL - DEPENDS - ${CMAKE_CURRENT_BINARY_DIR}/client/QueryClient.cpp - ${CMAKE_CURRENT_BINARY_DIR}/client/QueryClient.h - ${CMAKE_CURRENT_BINARY_DIR}/client/MutateClient.cpp - ${CMAKE_CURRENT_BINARY_DIR}/client/MutateClient.h - ${CMAKE_CURRENT_BINARY_DIR}/client/SubscribeClient.cpp - ${CMAKE_CURRENT_BINARY_DIR}/client/SubscribeClient.h - ${CMAKE_CURRENT_BINARY_DIR}/client/BenchmarkClient.cpp - ${CMAKE_CURRENT_BINARY_DIR}/client/BenchmarkClient.h) - endif() -endif() - -# separateschema -set(SEPARATE_SCHEMA_PATHS "") -file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/separate/today_schema_files SEPARATE_SCHEMA_FILES) -foreach(CPP_FILE IN LISTS SEPARATE_SCHEMA_FILES) - list(APPEND SEPARATE_SCHEMA_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/separate/${CPP_FILE}") -endforeach(CPP_FILE) - -add_library(separateschema STATIC ${SEPARATE_SCHEMA_PATHS}) -target_link_libraries(separateschema PUBLIC graphqlintrospection) -target_compile_definitions(separateschema PUBLIC IMPL_SEPARATE_TODAY) -target_include_directories(separateschema PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include - ${CMAKE_CURRENT_SOURCE_DIR}/separate) - -if(GRAPHQL_UPDATE_SAMPLES) - # wait for the sample update to complete - add_dependencies(separateschema update_samples) -endif() - -# separateschema_nointrospection -set(SEPARATE_NOINTROSPECTION_SCHEMA_PATHS "") -file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/separate_nointrospection/today_schema_files SEPARATE_NOINTROSPECTION_SCHEMA_FILES) -foreach(CPP_FILE IN LISTS SEPARATE_NOINTROSPECTION_SCHEMA_FILES) - list(APPEND SEPARATE_NOINTROSPECTION_SCHEMA_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/separate_nointrospection/${CPP_FILE}") -endforeach(CPP_FILE) - -add_library(separateschema_nointrospection STATIC ${SEPARATE_NOINTROSPECTION_SCHEMA_PATHS}) -target_link_libraries(separateschema_nointrospection PUBLIC graphqlservice) -target_compile_definitions(separateschema_nointrospection PUBLIC IMPL_SEPARATE_TODAY) -target_include_directories(separateschema_nointrospection PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include - ${CMAKE_CURRENT_SOURCE_DIR}/separate_nointrospection) - -if(GRAPHQL_UPDATE_SAMPLES) - # wait for the sample update to complete - add_dependencies(separateschema_nointrospection update_samples) -endif() - -# learnschema -set(LEARN_SCHEMA_PATHS "") -file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/learn/learn_schema_files LEARN_SCHEMA_FILES) -foreach(CPP_FILE IN LISTS LEARN_SCHEMA_FILES) - list(APPEND LEARN_SCHEMA_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/learn/${CPP_FILE}") -endforeach(CPP_FILE) - -add_library(learnschema STATIC ${LEARN_SCHEMA_PATHS}) -target_link_libraries(learnschema PUBLIC graphqlintrospection) -target_include_directories(learnschema PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include - ${CMAKE_CURRENT_SOURCE_DIR}/learn) - -if(GRAPHQL_UPDATE_SAMPLES) - # wait for the sample update to complete - add_dependencies(learnschema update_samples) -endif() - -# separategraphql -add_library(separategraphql STATIC today/TodayMock.cpp) -target_link_libraries(separategraphql PUBLIC separateschema) -target_include_directories(separategraphql PUBLIC today) - -# separategraphql_nointrospection -add_library(separategraphql_nointrospection STATIC today/TodayMock.cpp) -target_link_libraries(separategraphql_nointrospection PUBLIC separateschema_nointrospection) -target_include_directories(separategraphql_nointrospection PUBLIC today) - -# star_wars -add_library(star_wars STATIC - star_wars/DroidData.cpp - star_wars/HumanData.cpp - star_wars/QueryData.cpp - star_wars/ReviewData.cpp - star_wars/MutationData.cpp - star_wars/StarWarsData.cpp) -target_link_libraries(star_wars PUBLIC learnschema) -target_include_directories(star_wars PUBLIC star_wars) - -# sample -add_executable(sample today/sample.cpp) -target_link_libraries(sample PRIVATE - separategraphql - graphqljson) -target_include_directories(sample PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) - -# sample_nointrospection -add_executable(sample_nointrospection today/sample.cpp) -target_link_libraries(sample_nointrospection PRIVATE - separategraphql_nointrospection - graphqljson) -target_include_directories(sample_nointrospection PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) - -# learn_star_wars -add_executable(learn_star_wars star_wars/sample.cpp) -target_link_libraries(learn_star_wars PRIVATE - star_wars - graphqljson) -target_include_directories(learn_star_wars PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) - -if(WIN32 AND BUILD_SHARED_LIBS) - add_custom_command(OUTPUT copied_sample_dlls - COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - $ - $ - $ - $ - $ - ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} -E touch copied_sample_dlls - DEPENDS - graphqlservice - graphqlintrospection - graphqljson - graphqlpeg - graphqlresponse - graphqlclient) - - add_custom_target(copy_sample_dlls DEPENDS copied_sample_dlls) - - add_dependencies(sample copy_sample_dlls) - add_dependencies(sample_nointrospection copy_sample_dlls) -endif() - -# benchmark -add_executable(benchmark today/benchmark.cpp) -target_link_libraries(benchmark PRIVATE - separategraphql - graphqljson) -target_include_directories(benchmark PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) - -# benchmark_nointrospection -add_executable(benchmark_nointrospection today/benchmark.cpp) -target_link_libraries(benchmark_nointrospection PRIVATE - separategraphql_nointrospection - graphqljson) -target_include_directories(benchmark_nointrospection PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) - -if(WIN32 AND BUILD_SHARED_LIBS) - add_dependencies(benchmark copy_sample_dlls) - add_dependencies(benchmark_nointrospection copy_sample_dlls) -endif() - -if(GRAPHQL_BUILD_TESTS) - # tests - add_library(unifiedschema STATIC ${CMAKE_CURRENT_SOURCE_DIR}/unified/TodaySchema.cpp) - target_link_libraries(unifiedschema PUBLIC graphqlintrospection) - target_include_directories(unifiedschema PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include - ${CMAKE_CURRENT_SOURCE_DIR}/unified) - - if(GRAPHQL_UPDATE_SAMPLES) - # wait for the sample update to complete - add_dependencies(unifiedschema update_samples) - endif() - - add_library(unifiedgraphql STATIC today/TodayMock.cpp) - target_link_libraries(unifiedgraphql PUBLIC unifiedschema) - target_include_directories(unifiedgraphql PUBLIC today) - add_bigobj_flag(unifiedgraphql) - - add_library(unifiedschema_nointrospection STATIC ${CMAKE_CURRENT_SOURCE_DIR}/unified_nointrospection/TodaySchema.cpp) - target_link_libraries(unifiedschema_nointrospection PUBLIC graphqlservice) - target_include_directories(unifiedschema_nointrospection PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include - ${CMAKE_CURRENT_SOURCE_DIR}/unified_nointrospection) - - if(GRAPHQL_UPDATE_SAMPLES) - # wait for the sample update to complete - add_dependencies(unifiedschema_nointrospection update_samples) - endif() - - add_library(unifiedgraphql_nointrospection STATIC today/TodayMock.cpp) - target_link_libraries(unifiedgraphql_nointrospection PUBLIC unifiedschema_nointrospection) - target_include_directories(unifiedgraphql_nointrospection PUBLIC today) - add_bigobj_flag(unifiedgraphql_nointrospection) - - add_library(validationgraphql STATIC - ${CMAKE_CURRENT_SOURCE_DIR}/validation/ValidationMock.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/validation/ValidationSchema.cpp) - target_link_libraries(validationgraphql PUBLIC graphqlintrospection) - target_include_directories(validationgraphql PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include - ${CMAKE_CURRENT_SOURCE_DIR}/validation) - add_bigobj_flag(validationgraphql) - - if(GRAPHQL_UPDATE_SAMPLES) - # wait for the sample update to complete - add_dependencies(validationgraphql update_samples) - endif() -endif() - -# todayclient -add_library(todayclient STATIC - ${CMAKE_CURRENT_SOURCE_DIR}/client/QueryClient.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/client/MutateClient.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/client/SubscribeClient.cpp) -target_link_libraries(todayclient PUBLIC graphqlclient) -target_include_directories(todayclient PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include - ${CMAKE_CURRENT_SOURCE_DIR}/client) - -if(GRAPHQL_UPDATE_SAMPLES AND GRAPHQL_BUILD_CLIENTGEN) - # wait for the sample update to complete - add_dependencies(todayclient update_client_samples) -endif() - -# client_benchmark -add_executable(client_benchmark - ${CMAKE_CURRENT_SOURCE_DIR}/client/BenchmarkClient.cpp - client/benchmark.cpp) -target_link_libraries(client_benchmark PRIVATE - separategraphql - todayclient - graphqlclient) -target_include_directories(client_benchmark PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include - ${CMAKE_CURRENT_SOURCE_DIR}/client) - -if(WIN32 AND BUILD_SHARED_LIBS) - add_dependencies(client_benchmark copy_sample_dlls) -endif() +add_subdirectory(client) +add_subdirectory(learn) +add_subdirectory(today) +add_subdirectory(validation) diff --git a/samples/client/CMakeLists.txt b/samples/client/CMakeLists.txt new file mode 100644 index 00000000..b220bdc8 --- /dev/null +++ b/samples/client/CMakeLists.txt @@ -0,0 +1,40 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +add_subdirectory(query) +add_subdirectory(mutate) +add_subdirectory(subscribe) + +add_subdirectory(benchmark) + +# client_benchmark +add_executable(client_benchmark benchmark.cpp) +target_link_libraries(client_benchmark PRIVATE + todaygraphql + benchmark_client) + +if(WIN32 AND BUILD_SHARED_LIBS) + add_custom_command(OUTPUT copied_sample_dlls + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $ + $ + $ + $ + $ + ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/copied_sample_dlls + DEPENDS + graphqlservice + graphqlintrospection + graphqljson + graphqlpeg + graphqlresponse + graphqlclient) + + add_custom_target(copy_client_sample_dlls DEPENDS copied_sample_dlls) + + add_dependencies(client_benchmark copy_client_sample_dlls) +endif() diff --git a/samples/client/benchmark.cpp b/samples/client/benchmark.cpp index 3f002876..ddcfab6b 100644 --- a/samples/client/benchmark.cpp +++ b/samples/client/benchmark.cpp @@ -141,8 +141,7 @@ int main(int argc, char** argv) auto query = GetRequestObject(); const auto startResolve = std::chrono::steady_clock::now(); - auto response = - service->resolve(nullptr, query, "", response::Value(response::Type::Map)).get(); + auto response = service->resolve({ query }).get(); const auto startParseServiceResponse = std::chrono::steady_clock::now(); auto serviceResponse = client::parseServiceResponse(std::move(response)); const auto startParseResponse = std::chrono::steady_clock::now(); diff --git a/samples/client/BenchmarkClient.cpp b/samples/client/benchmark/BenchmarkClient.cpp similarity index 89% rename from samples/client/BenchmarkClient.cpp rename to samples/client/benchmark/BenchmarkClient.cpp index ab677a16..11900a89 100644 --- a/samples/client/BenchmarkClient.cpp +++ b/samples/client/benchmark/BenchmarkClient.cpp @@ -7,8 +7,8 @@ #include #include -#include #include +#include #include using namespace std::literals; @@ -18,7 +18,7 @@ namespace graphql::client { using namespace query::Query; template <> -Response::appointments_AppointmentConnection::pageInfo_PageInfo ModifiedResponse::parse(response::Value&& response) +Response::appointments_AppointmentConnection::pageInfo_PageInfo ModifiedResponse::parse(response::Value response) { Response::appointments_AppointmentConnection::pageInfo_PageInfo result; @@ -30,7 +30,7 @@ Response::appointments_AppointmentConnection::pageInfo_PageInfo ModifiedResponse { if (member.first == R"js(hasNextPage)js"sv) { - result.hasNextPage = ModifiedResponse::parse(std::move(member.second)); + result.hasNextPage = ModifiedResponse::parse(std::move(member.second)); continue; } } @@ -40,7 +40,7 @@ Response::appointments_AppointmentConnection::pageInfo_PageInfo ModifiedResponse } template <> -Response::appointments_AppointmentConnection::edges_AppointmentEdge::node_Appointment ModifiedResponse::parse(response::Value&& response) +Response::appointments_AppointmentConnection::edges_AppointmentEdge::node_Appointment ModifiedResponse::parse(response::Value response) { Response::appointments_AppointmentConnection::edges_AppointmentEdge::node_Appointment result; @@ -62,12 +62,12 @@ Response::appointments_AppointmentConnection::edges_AppointmentEdge::node_Appoin } if (member.first == R"js(subject)js"sv) { - result.subject = ModifiedResponse::parse(std::move(member.second)); + result.subject = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(isNow)js"sv) { - result.isNow = ModifiedResponse::parse(std::move(member.second)); + result.isNow = ModifiedResponse::parse(std::move(member.second)); continue; } } @@ -77,7 +77,7 @@ Response::appointments_AppointmentConnection::edges_AppointmentEdge::node_Appoin } template <> -Response::appointments_AppointmentConnection::edges_AppointmentEdge ModifiedResponse::parse(response::Value&& response) +Response::appointments_AppointmentConnection::edges_AppointmentEdge ModifiedResponse::parse(response::Value response) { Response::appointments_AppointmentConnection::edges_AppointmentEdge result; @@ -99,7 +99,7 @@ Response::appointments_AppointmentConnection::edges_AppointmentEdge ModifiedResp } template <> -Response::appointments_AppointmentConnection ModifiedResponse::parse(response::Value&& response) +Response::appointments_AppointmentConnection ModifiedResponse::parse(response::Value response) { Response::appointments_AppointmentConnection result; @@ -167,7 +167,7 @@ const peg::ast& GetRequestObject() noexcept return s_request; } -Response parseResponse(response::Value&& response) +Response parseResponse(response::Value response) { Response result; diff --git a/samples/client/BenchmarkClient.h b/samples/client/benchmark/BenchmarkClient.h similarity index 82% rename from samples/client/BenchmarkClient.h rename to samples/client/benchmark/BenchmarkClient.h index 520eeead..14b7849e 100644 --- a/samples/client/BenchmarkClient.h +++ b/samples/client/benchmark/BenchmarkClient.h @@ -14,9 +14,9 @@ #include "graphqlservice/internal/Version.h" -// Check if the library version is compatible with clientgen 3.6.0 -static_assert(graphql::internal::MajorVersion == 3, "regenerate with clientgen: major version mismatch"); -static_assert(graphql::internal::MinorVersion == 6, "regenerate with clientgen: minor version mismatch"); +// Check if the library version is compatible with clientgen 4.0.0 +static_assert(graphql::internal::MajorVersion == 4, "regenerate with clientgen: major version mismatch"); +static_assert(graphql::internal::MinorVersion == 0, "regenerate with clientgen: minor version mismatch"); #include #include @@ -59,7 +59,7 @@ struct Response { struct pageInfo_PageInfo { - response::BooleanType hasNextPage {}; + bool hasNextPage {}; }; struct edges_AppointmentEdge @@ -68,8 +68,8 @@ struct Response { response::IdType id {}; std::optional when {}; - std::optional subject {}; - response::BooleanType isNow {}; + std::optional subject {}; + bool isNow {}; }; std::optional node {}; @@ -82,7 +82,7 @@ struct Response appointments_AppointmentConnection appointments {}; }; -Response parseResponse(response::Value&& response); +Response parseResponse(response::Value response); } // namespace graphql::client::query::Query diff --git a/samples/client/benchmark/CMakeLists.txt b/samples/client/benchmark/CMakeLists.txt new file mode 100644 index 00000000..ea0ab74c --- /dev/null +++ b/samples/client/benchmark/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +# Normally this would be handled by find_package(cppgraphqlgen CONFIG). +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/cppgraphqlgen-functions.cmake) + +if(GRAPHQL_UPDATE_SAMPLES AND GRAPHQL_BUILD_CLIENTGEN) + update_graphql_client_files(benchmark ../../today/schema.today.graphql client.benchmark.today.graphql Benchmark benchmark) +endif() + +add_graphql_client_target(benchmark) diff --git a/samples/client/benchmark/benchmark_client_files b/samples/client/benchmark/benchmark_client_files new file mode 100644 index 00000000..2d3350f3 --- /dev/null +++ b/samples/client/benchmark/benchmark_client_files @@ -0,0 +1 @@ +BenchmarkClient.cpp diff --git a/samples/client.benchmark.today.graphql b/samples/client/benchmark/client.benchmark.today.graphql similarity index 100% rename from samples/client.benchmark.today.graphql rename to samples/client/benchmark/client.benchmark.today.graphql diff --git a/samples/client/mutate/CMakeLists.txt b/samples/client/mutate/CMakeLists.txt new file mode 100644 index 00000000..61b3ab67 --- /dev/null +++ b/samples/client/mutate/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +# Normally this would be handled by find_package(cppgraphqlgen CONFIG). +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/cppgraphqlgen-functions.cmake) + +if(GRAPHQL_UPDATE_SAMPLES AND GRAPHQL_BUILD_CLIENTGEN) + update_graphql_client_files(mutate ../../today/schema.today.graphql mutate.today.graphql Mutate mutate) +endif() + +add_graphql_client_target(mutate) diff --git a/samples/client/MutateClient.cpp b/samples/client/mutate/MutateClient.cpp similarity index 82% rename from samples/client/MutateClient.cpp rename to samples/client/mutate/MutateClient.cpp index d79aac5a..2eb9325c 100644 --- a/samples/client/MutateClient.cpp +++ b/samples/client/mutate/MutateClient.cpp @@ -7,8 +7,8 @@ #include #include -#include #include +#include #include using namespace std::literals; @@ -29,7 +29,7 @@ response::Value ModifiedVariable::serialize(TaskState&& value) { response::Value result { response::Type::EnumValue }; - result.set(response::StringType { s_namesTaskState[static_cast(value)] }); + result.set(std::string { s_namesTaskState[static_cast(value)] }); return result; } @@ -41,21 +41,21 @@ response::Value ModifiedVariable::serialize(Variab result.emplace_back(R"js(id)js"s, ModifiedVariable::serialize(std::move(inputValue.id))); result.emplace_back(R"js(testTaskState)js"s, ModifiedVariable::serialize(std::move(inputValue.testTaskState))); - result.emplace_back(R"js(isComplete)js"s, ModifiedVariable::serialize(std::move(inputValue.isComplete))); - result.emplace_back(R"js(clientMutationId)js"s, ModifiedVariable::serialize(std::move(inputValue.clientMutationId))); + result.emplace_back(R"js(isComplete)js"s, ModifiedVariable::serialize(std::move(inputValue.isComplete))); + result.emplace_back(R"js(clientMutationId)js"s, ModifiedVariable::serialize(std::move(inputValue.clientMutationId))); return result; } template <> -TaskState ModifiedResponse::parse(response::Value&& value) +TaskState ModifiedResponse::parse(response::Value value) { if (!value.maybe_enum()) { throw std::logic_error { "not a valid TaskState value" }; } - const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.release()); + const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.release()); if (itr == s_namesTaskState.cend()) { @@ -66,7 +66,7 @@ TaskState ModifiedResponse::parse(response::Value&& value) } template <> -Response::completedTask_CompleteTaskPayload::completedTask_Task ModifiedResponse::parse(response::Value&& response) +Response::completedTask_CompleteTaskPayload::completedTask_Task ModifiedResponse::parse(response::Value response) { Response::completedTask_CompleteTaskPayload::completedTask_Task result; @@ -83,12 +83,12 @@ Response::completedTask_CompleteTaskPayload::completedTask_Task ModifiedResponse } if (member.first == R"js(title)js"sv) { - result.title = ModifiedResponse::parse(std::move(member.second)); + result.title = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(isComplete)js"sv) { - result.isComplete = ModifiedResponse::parse(std::move(member.second)); + result.isComplete = ModifiedResponse::parse(std::move(member.second)); continue; } } @@ -98,7 +98,7 @@ Response::completedTask_CompleteTaskPayload::completedTask_Task ModifiedResponse } template <> -Response::completedTask_CompleteTaskPayload ModifiedResponse::parse(response::Value&& response) +Response::completedTask_CompleteTaskPayload ModifiedResponse::parse(response::Value response) { Response::completedTask_CompleteTaskPayload result; @@ -115,7 +115,7 @@ Response::completedTask_CompleteTaskPayload ModifiedResponse::parse(std::move(member.second)); + result.clientMutationId = ModifiedResponse::parse(std::move(member.second)); continue; } } @@ -170,7 +170,7 @@ response::Value serializeVariables(Variables&& variables) return result; } -Response parseResponse(response::Value&& response) +Response parseResponse(response::Value response) { Response result; diff --git a/samples/client/MutateClient.h b/samples/client/mutate/MutateClient.h similarity index 79% rename from samples/client/MutateClient.h rename to samples/client/mutate/MutateClient.h index 046a90d7..61947c0b 100644 --- a/samples/client/MutateClient.h +++ b/samples/client/mutate/MutateClient.h @@ -14,9 +14,9 @@ #include "graphqlservice/internal/Version.h" -// Check if the library version is compatible with clientgen 3.6.0 -static_assert(graphql::internal::MajorVersion == 3, "regenerate with clientgen: major version mismatch"); -static_assert(graphql::internal::MinorVersion == 6, "regenerate with clientgen: minor version mismatch"); +// Check if the library version is compatible with clientgen 4.0.0 +static_assert(graphql::internal::MajorVersion == 4, "regenerate with clientgen: major version mismatch"); +static_assert(graphql::internal::MinorVersion == 0, "regenerate with clientgen: minor version mismatch"); #include #include @@ -62,8 +62,8 @@ struct Variables { response::IdType id {}; std::optional testTaskState {}; - std::optional isComplete {}; - std::optional clientMutationId {}; + std::optional isComplete {}; + std::optional clientMutationId {}; }; CompleteTaskInput input {}; @@ -78,18 +78,18 @@ struct Response struct completedTask_Task { response::IdType completedTaskId {}; - std::optional title {}; - response::BooleanType isComplete {}; + std::optional title {}; + bool isComplete {}; }; std::optional completedTask {}; - std::optional clientMutationId {}; + std::optional clientMutationId {}; }; completedTask_CompleteTaskPayload completedTask {}; }; -Response parseResponse(response::Value&& response); +Response parseResponse(response::Value response); } // namespace graphql::client::mutation::CompleteTaskMutation diff --git a/samples/mutate.today.graphql b/samples/client/mutate/mutate.today.graphql similarity index 100% rename from samples/mutate.today.graphql rename to samples/client/mutate/mutate.today.graphql diff --git a/samples/client/mutate/mutate_client_files b/samples/client/mutate/mutate_client_files new file mode 100644 index 00000000..b6aead9c --- /dev/null +++ b/samples/client/mutate/mutate_client_files @@ -0,0 +1 @@ +MutateClient.cpp diff --git a/samples/client/query/CMakeLists.txt b/samples/client/query/CMakeLists.txt new file mode 100644 index 00000000..dd483b6c --- /dev/null +++ b/samples/client/query/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +# Normally this would be handled by find_package(cppgraphqlgen CONFIG). +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/cppgraphqlgen-functions.cmake) + +if(GRAPHQL_UPDATE_SAMPLES AND GRAPHQL_BUILD_CLIENTGEN) + update_graphql_client_files(query ../../today/schema.today.graphql query.today.graphql Query query) +endif() + +add_graphql_client_target(query) diff --git a/samples/client/QueryClient.cpp b/samples/client/query/QueryClient.cpp similarity index 83% rename from samples/client/QueryClient.cpp rename to samples/client/query/QueryClient.cpp index 6277b593..60e260df 100644 --- a/samples/client/QueryClient.cpp +++ b/samples/client/query/QueryClient.cpp @@ -7,8 +7,8 @@ #include #include -#include #include +#include #include using namespace std::literals; @@ -25,14 +25,14 @@ static const std::array s_namesTaskState = { }; template <> -TaskState ModifiedResponse::parse(response::Value&& value) +TaskState ModifiedResponse::parse(response::Value value) { if (!value.maybe_enum()) { throw std::logic_error { "not a valid TaskState value" }; } - const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.release()); + const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.release()); if (itr == s_namesTaskState.cend()) { @@ -43,7 +43,7 @@ TaskState ModifiedResponse::parse(response::Value&& value) } template <> -Response::appointments_AppointmentConnection::edges_AppointmentEdge::node_Appointment ModifiedResponse::parse(response::Value&& response) +Response::appointments_AppointmentConnection::edges_AppointmentEdge::node_Appointment ModifiedResponse::parse(response::Value response) { Response::appointments_AppointmentConnection::edges_AppointmentEdge::node_Appointment result; @@ -60,7 +60,7 @@ Response::appointments_AppointmentConnection::edges_AppointmentEdge::node_Appoin } if (member.first == R"js(subject)js"sv) { - result.subject = ModifiedResponse::parse(std::move(member.second)); + result.subject = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(when)js"sv) @@ -70,12 +70,12 @@ Response::appointments_AppointmentConnection::edges_AppointmentEdge::node_Appoin } if (member.first == R"js(isNow)js"sv) { - result.isNow = ModifiedResponse::parse(std::move(member.second)); + result.isNow = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(__typename)js"sv) { - result._typename = ModifiedResponse::parse(std::move(member.second)); + result._typename = ModifiedResponse::parse(std::move(member.second)); continue; } } @@ -85,7 +85,7 @@ Response::appointments_AppointmentConnection::edges_AppointmentEdge::node_Appoin } template <> -Response::appointments_AppointmentConnection::edges_AppointmentEdge ModifiedResponse::parse(response::Value&& response) +Response::appointments_AppointmentConnection::edges_AppointmentEdge ModifiedResponse::parse(response::Value response) { Response::appointments_AppointmentConnection::edges_AppointmentEdge result; @@ -107,7 +107,7 @@ Response::appointments_AppointmentConnection::edges_AppointmentEdge ModifiedResp } template <> -Response::appointments_AppointmentConnection ModifiedResponse::parse(response::Value&& response) +Response::appointments_AppointmentConnection ModifiedResponse::parse(response::Value response) { Response::appointments_AppointmentConnection result; @@ -129,7 +129,7 @@ Response::appointments_AppointmentConnection ModifiedResponse -Response::tasks_TaskConnection::edges_TaskEdge::node_Task ModifiedResponse::parse(response::Value&& response) +Response::tasks_TaskConnection::edges_TaskEdge::node_Task ModifiedResponse::parse(response::Value response) { Response::tasks_TaskConnection::edges_TaskEdge::node_Task result; @@ -146,17 +146,17 @@ Response::tasks_TaskConnection::edges_TaskEdge::node_Task ModifiedResponse::parse(std::move(member.second)); + result.title = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(isComplete)js"sv) { - result.isComplete = ModifiedResponse::parse(std::move(member.second)); + result.isComplete = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(__typename)js"sv) { - result._typename = ModifiedResponse::parse(std::move(member.second)); + result._typename = ModifiedResponse::parse(std::move(member.second)); continue; } } @@ -166,7 +166,7 @@ Response::tasks_TaskConnection::edges_TaskEdge::node_Task ModifiedResponse -Response::tasks_TaskConnection::edges_TaskEdge ModifiedResponse::parse(response::Value&& response) +Response::tasks_TaskConnection::edges_TaskEdge ModifiedResponse::parse(response::Value response) { Response::tasks_TaskConnection::edges_TaskEdge result; @@ -188,7 +188,7 @@ Response::tasks_TaskConnection::edges_TaskEdge ModifiedResponse -Response::tasks_TaskConnection ModifiedResponse::parse(response::Value&& response) +Response::tasks_TaskConnection ModifiedResponse::parse(response::Value response) { Response::tasks_TaskConnection result; @@ -210,7 +210,7 @@ Response::tasks_TaskConnection ModifiedResponse: } template <> -Response::unreadCounts_FolderConnection::edges_FolderEdge::node_Folder ModifiedResponse::parse(response::Value&& response) +Response::unreadCounts_FolderConnection::edges_FolderEdge::node_Folder ModifiedResponse::parse(response::Value response) { Response::unreadCounts_FolderConnection::edges_FolderEdge::node_Folder result; @@ -227,17 +227,17 @@ Response::unreadCounts_FolderConnection::edges_FolderEdge::node_Folder ModifiedR } if (member.first == R"js(name)js"sv) { - result.name = ModifiedResponse::parse(std::move(member.second)); + result.name = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(unreadCount)js"sv) { - result.unreadCount = ModifiedResponse::parse(std::move(member.second)); + result.unreadCount = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(__typename)js"sv) { - result._typename = ModifiedResponse::parse(std::move(member.second)); + result._typename = ModifiedResponse::parse(std::move(member.second)); continue; } } @@ -247,7 +247,7 @@ Response::unreadCounts_FolderConnection::edges_FolderEdge::node_Folder ModifiedR } template <> -Response::unreadCounts_FolderConnection::edges_FolderEdge ModifiedResponse::parse(response::Value&& response) +Response::unreadCounts_FolderConnection::edges_FolderEdge ModifiedResponse::parse(response::Value response) { Response::unreadCounts_FolderConnection::edges_FolderEdge result; @@ -269,7 +269,7 @@ Response::unreadCounts_FolderConnection::edges_FolderEdge ModifiedResponse -Response::unreadCounts_FolderConnection ModifiedResponse::parse(response::Value&& response) +Response::unreadCounts_FolderConnection ModifiedResponse::parse(response::Value response) { Response::unreadCounts_FolderConnection result; @@ -291,7 +291,7 @@ Response::unreadCounts_FolderConnection ModifiedResponse -Response::anyType_UnionType ModifiedResponse::parse(response::Value&& response) +Response::anyType_UnionType ModifiedResponse::parse(response::Value response) { Response::anyType_UnionType result; @@ -303,7 +303,7 @@ Response::anyType_UnionType ModifiedResponse::parse { if (member.first == R"js(__typename)js"sv) { - result._typename = ModifiedResponse::parse(std::move(member.second)); + result._typename = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(id)js"sv) @@ -313,17 +313,17 @@ Response::anyType_UnionType ModifiedResponse::parse } if (member.first == R"js(title)js"sv) { - result.title = ModifiedResponse::parse(std::move(member.second)); + result.title = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(isComplete)js"sv) { - result.isComplete = ModifiedResponse::parse(std::move(member.second)); + result.isComplete = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(subject)js"sv) { - result.subject = ModifiedResponse::parse(std::move(member.second)); + result.subject = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(when)js"sv) @@ -333,7 +333,7 @@ Response::anyType_UnionType ModifiedResponse::parse } if (member.first == R"js(isNow)js"sv) { - result.isNow = ModifiedResponse::parse(std::move(member.second)); + result.isNow = ModifiedResponse::parse(std::move(member.second)); continue; } } @@ -424,7 +424,7 @@ const peg::ast& GetRequestObject() noexcept return s_request; } -Response parseResponse(response::Value&& response) +Response parseResponse(response::Value response) { Response result; diff --git a/samples/client/QueryClient.h b/samples/client/query/QueryClient.h similarity index 79% rename from samples/client/QueryClient.h rename to samples/client/query/QueryClient.h index d7b58d7a..35c24bb9 100644 --- a/samples/client/QueryClient.h +++ b/samples/client/query/QueryClient.h @@ -14,9 +14,9 @@ #include "graphqlservice/internal/Version.h" -// Check if the library version is compatible with clientgen 3.6.0 -static_assert(graphql::internal::MajorVersion == 3, "regenerate with clientgen: major version mismatch"); -static_assert(graphql::internal::MinorVersion == 6, "regenerate with clientgen: minor version mismatch"); +// Check if the library version is compatible with clientgen 4.0.0 +static_assert(graphql::internal::MajorVersion == 4, "regenerate with clientgen: major version mismatch"); +static_assert(graphql::internal::MinorVersion == 0, "regenerate with clientgen: minor version mismatch"); #include #include @@ -110,10 +110,10 @@ struct Response struct node_Appointment { response::IdType id {}; - std::optional subject {}; + std::optional subject {}; std::optional when {}; - response::BooleanType isNow {}; - response::StringType _typename {}; + bool isNow {}; + std::string _typename {}; }; std::optional node {}; @@ -129,9 +129,9 @@ struct Response struct node_Task { response::IdType id {}; - std::optional title {}; - response::BooleanType isComplete {}; - response::StringType _typename {}; + std::optional title {}; + bool isComplete {}; + std::string _typename {}; }; std::optional node {}; @@ -147,9 +147,9 @@ struct Response struct node_Folder { response::IdType id {}; - std::optional name {}; - response::IntType unreadCount {}; - response::StringType _typename {}; + std::optional name {}; + int unreadCount {}; + std::string _typename {}; }; std::optional node {}; @@ -160,13 +160,13 @@ struct Response struct anyType_UnionType { - response::StringType _typename {}; + std::string _typename {}; response::IdType id {}; - std::optional title {}; - response::BooleanType isComplete {}; - std::optional subject {}; + std::optional title {}; + bool isComplete {}; + std::optional subject {}; std::optional when {}; - response::BooleanType isNow {}; + bool isNow {}; }; appointments_AppointmentConnection appointments {}; @@ -176,7 +176,7 @@ struct Response std::vector> anyType {}; }; -Response parseResponse(response::Value&& response); +Response parseResponse(response::Value response); } // namespace graphql::client::query::Query diff --git a/samples/query.today.graphql b/samples/client/query/query.today.graphql similarity index 100% rename from samples/query.today.graphql rename to samples/client/query/query.today.graphql diff --git a/samples/client/query/query_client_files b/samples/client/query/query_client_files new file mode 100644 index 00000000..849c8c17 --- /dev/null +++ b/samples/client/query/query_client_files @@ -0,0 +1 @@ +QueryClient.cpp diff --git a/samples/client/subscribe/CMakeLists.txt b/samples/client/subscribe/CMakeLists.txt new file mode 100644 index 00000000..fb3ea5eb --- /dev/null +++ b/samples/client/subscribe/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +# Normally this would be handled by find_package(cppgraphqlgen CONFIG). +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/cppgraphqlgen-functions.cmake) + +if(GRAPHQL_UPDATE_SAMPLES AND GRAPHQL_BUILD_CLIENTGEN) + update_graphql_client_files(subscribe ../../today/schema.today.graphql subscribe.today.graphql Subscribe subscribe) +endif() + +add_graphql_client_target(subscribe) diff --git a/samples/client/SubscribeClient.cpp b/samples/client/subscribe/SubscribeClient.cpp similarity index 87% rename from samples/client/SubscribeClient.cpp rename to samples/client/subscribe/SubscribeClient.cpp index d9bae4f4..c2b250ef 100644 --- a/samples/client/SubscribeClient.cpp +++ b/samples/client/subscribe/SubscribeClient.cpp @@ -7,8 +7,8 @@ #include #include -#include #include +#include #include using namespace std::literals; @@ -18,7 +18,7 @@ namespace graphql::client { using namespace subscription::TestSubscription; template <> -Response::nextAppointment_Appointment ModifiedResponse::parse(response::Value&& response) +Response::nextAppointment_Appointment ModifiedResponse::parse(response::Value response) { Response::nextAppointment_Appointment result; @@ -40,12 +40,12 @@ Response::nextAppointment_Appointment ModifiedResponse::parse(std::move(member.second)); + result.subject = ModifiedResponse::parse(std::move(member.second)); continue; } if (member.first == R"js(isNow)js"sv) { - result.isNow = ModifiedResponse::parse(std::move(member.second)); + result.isNow = ModifiedResponse::parse(std::move(member.second)); continue; } } @@ -89,7 +89,7 @@ const peg::ast& GetRequestObject() noexcept return s_request; } -Response parseResponse(response::Value&& response) +Response parseResponse(response::Value response) { Response result; diff --git a/samples/client/SubscribeClient.h b/samples/client/subscribe/SubscribeClient.h similarity index 82% rename from samples/client/SubscribeClient.h rename to samples/client/subscribe/SubscribeClient.h index 11dc1575..c915885f 100644 --- a/samples/client/SubscribeClient.h +++ b/samples/client/subscribe/SubscribeClient.h @@ -14,9 +14,9 @@ #include "graphqlservice/internal/Version.h" -// Check if the library version is compatible with clientgen 3.6.0 -static_assert(graphql::internal::MajorVersion == 3, "regenerate with clientgen: major version mismatch"); -static_assert(graphql::internal::MinorVersion == 6, "regenerate with clientgen: minor version mismatch"); +// Check if the library version is compatible with clientgen 4.0.0 +static_assert(graphql::internal::MajorVersion == 4, "regenerate with clientgen: major version mismatch"); +static_assert(graphql::internal::MinorVersion == 0, "regenerate with clientgen: minor version mismatch"); #include #include @@ -52,14 +52,14 @@ struct Response { response::IdType nextAppointmentId {}; std::optional when {}; - std::optional subject {}; - response::BooleanType isNow {}; + std::optional subject {}; + bool isNow {}; }; std::optional nextAppointment {}; }; -Response parseResponse(response::Value&& response); +Response parseResponse(response::Value response); } // namespace graphql::client::subscription::TestSubscription diff --git a/samples/subscribe.today.graphql b/samples/client/subscribe/subscribe.today.graphql similarity index 100% rename from samples/subscribe.today.graphql rename to samples/client/subscribe/subscribe.today.graphql diff --git a/samples/client/subscribe/subscribe_client_files b/samples/client/subscribe/subscribe_client_files new file mode 100644 index 00000000..39049156 --- /dev/null +++ b/samples/client/subscribe/subscribe_client_files @@ -0,0 +1 @@ +SubscribeClient.cpp diff --git a/samples/learn/CMakeLists.txt b/samples/learn/CMakeLists.txt new file mode 100644 index 00000000..cda78c75 --- /dev/null +++ b/samples/learn/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +add_subdirectory(schema) +add_library(star_wars STATIC + HeroData.cpp + DroidData.cpp + HumanData.cpp + QueryData.cpp + ReviewData.cpp + MutationData.cpp + StarWarsData.cpp) +target_link_libraries(star_wars PUBLIC learn_schema) +target_include_directories(star_wars PUBLIC star_wars) + +add_executable(learn_star_wars sample.cpp) +target_link_libraries(learn_star_wars PRIVATE + star_wars + graphqljson) + +if(WIN32 AND BUILD_SHARED_LIBS) + add_custom_command(OUTPUT copied_sample_dlls + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $ + $ + $ + $ + ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E touch copied_sample_dlls + DEPENDS + graphqlservice + graphqlintrospection + graphqljson + graphqlpeg + graphqlresponse) + + add_custom_target(copy_learn_sample_dlls DEPENDS copied_sample_dlls) + + add_dependencies(learn_star_wars copy_learn_sample_dlls) +endif() diff --git a/samples/learn/DroidData.cpp b/samples/learn/DroidData.cpp new file mode 100644 index 00000000..630d6ee8 --- /dev/null +++ b/samples/learn/DroidData.cpp @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "DroidData.h" + +#include "HumanData.h" + +namespace graphql::learn { + +Droid::Droid(std::string&& id, std::optional&& name, std::vector&& appearsIn, + std::optional&& primaryFunction) noexcept + : id_ { std::move(id) } + , name_ { std::move(name) } + , appearsIn_ { std::move(appearsIn) } + , primaryFunction_ { std::move(primaryFunction) } +{ +} + +void Droid::addFriends( + std::vector, std::shared_ptr>> friends) noexcept +{ + friends_.resize(friends.size()); + + std::transform(friends.begin(), + friends.end(), + friends_.begin(), + [](const auto& spFriend) noexcept { + return std::visit( + [](const auto& hero) noexcept { + return WeakHero { + std::weak_ptr::element_type> { hero } + }; + }, + spFriend); + }); +} + +const std::string& Droid::getId() const noexcept +{ + return id_; +} + +const std::optional& Droid::getName() const noexcept +{ + return name_; +} + +std::optional>> Droid::getFriends() const noexcept +{ + std::vector> result(friends_.size()); + + std::transform(friends_.begin(), + friends_.end(), + result.begin(), + [](const auto& wpFriend) noexcept { + return make_hero(wpFriend); + }); + result.erase(std::remove(result.begin(), result.end(), std::shared_ptr {}), + result.end()); + + return result.empty() ? std::nullopt : std::make_optional(std::move(result)); +} + +std::optional>> Droid::getAppearsIn() const noexcept +{ + std::vector> result(appearsIn_.size()); + + std::transform(appearsIn_.begin(), + appearsIn_.end(), + result.begin(), + [](const auto& entry) noexcept { + return std::make_optional(entry); + }); + + return result.empty() ? std::nullopt : std::make_optional(std::move(result)); +} + +const std::optional& Droid::getPrimaryFunction() const noexcept +{ + return primaryFunction_; +} + +} // namespace graphql::learn diff --git a/samples/learn/DroidData.h b/samples/learn/DroidData.h new file mode 100644 index 00000000..6d59bdad --- /dev/null +++ b/samples/learn/DroidData.h @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef DROIDDATA_H +#define DROIDDATA_H + +#include "HeroData.h" + +#include "DroidObject.h" + +namespace graphql::learn { + +class Human; + +class Droid +{ +public: + explicit Droid(std::string&& id, std::optional&& name, + std::vector&& appearsIn, std::optional&& primaryFunction) noexcept; + + void addFriends(std::vector friends) noexcept; + + const std::string& getId() const noexcept; + const std::optional& getName() const noexcept; + std::optional>> getFriends() const noexcept; + std::optional>> getAppearsIn() const noexcept; + const std::optional& getPrimaryFunction() const noexcept; + +private: + const std::string id_; + const std::optional name_; + const std::vector appearsIn_; + const std::optional primaryFunction_; + + std::vector friends_; +}; + +} // namespace graphql::learn + +#endif // DROIDDATA_H diff --git a/samples/learn/DroidObject.cpp b/samples/learn/DroidObject.cpp deleted file mode 100644 index b12ce167..00000000 --- a/samples/learn/DroidObject.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "StarWarsObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::learn { -namespace object { - -Droid::Droid() - : service::Object({ - "Character", - "Droid" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(friends)gql"sv, [this](service::ResolverParams&& params) { return resolveFriends(std::move(params)); } }, - { R"gql(appearsIn)gql"sv, [this](service::ResolverParams&& params) { return resolveAppearsIn(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(primaryFunction)gql"sv, [this](service::ResolverParams&& params) { return resolvePrimaryFunction(std::move(params)); } } - }) -{ -} - -service::FieldResult Droid::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Droid::getId is not implemented)ex"); -} - -std::future Droid::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Droid::getName(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Droid::getName is not implemented)ex"); -} - -std::future Droid::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> Droid::getFriends(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Droid::getFriends is not implemented)ex"); -} - -std::future Droid::resolveFriends(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getFriends(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> Droid::getAppearsIn(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Droid::getAppearsIn is not implemented)ex"); -} - -std::future Droid::resolveAppearsIn(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getAppearsIn(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Droid::getPrimaryFunction(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Droid::getPrimaryFunction is not implemented)ex"); -} - -std::future Droid::resolvePrimaryFunction(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPrimaryFunction(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Droid::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Droid)gql" }, std::move(params)); -} - -} // namespace object - -void AddDroidDetails(std::shared_ptr typeDroid, const std::shared_ptr& schema) -{ - typeDroid->AddInterfaces({ - std::static_pointer_cast(schema->LookupType(R"gql(Character)gql"sv)) - }); - typeDroid->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(friends)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Character"))), - schema::Field::Make(R"gql(appearsIn)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Episode"))), - schema::Field::Make(R"gql(primaryFunction)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); -} - -} // namespace graphql::learn diff --git a/samples/learn/DroidObject.h b/samples/learn/DroidObject.h deleted file mode 100644 index 0c79a9ea..00000000 --- a/samples/learn/DroidObject.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef DROIDOBJECT_H -#define DROIDOBJECT_H - -#include "StarWarsSchema.h" - -namespace graphql::learn::object { - -class Droid - : public service::Object - , public Character -{ -protected: - explicit Droid(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getName(service::FieldParams&& params) const override; - virtual service::FieldResult>>> getFriends(service::FieldParams&& params) const override; - virtual service::FieldResult>>> getAppearsIn(service::FieldParams&& params) const override; - virtual service::FieldResult> getPrimaryFunction(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveName(service::ResolverParams&& params); - std::future resolveFriends(service::ResolverParams&& params); - std::future resolveAppearsIn(service::ResolverParams&& params); - std::future resolvePrimaryFunction(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::learn::object - -#endif // DROIDOBJECT_H diff --git a/samples/learn/HeroData.cpp b/samples/learn/HeroData.cpp new file mode 100644 index 00000000..757c382c --- /dev/null +++ b/samples/learn/HeroData.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "HeroData.h" + +#include "DroidData.h" +#include "HumanData.h" + +#include "CharacterObject.h" + +namespace graphql::learn { + +std::shared_ptr make_hero(const SharedHero& hero) noexcept +{ + return std::visit( + [](const auto& hero) noexcept { + using hero_t = std::decay_t; + + if constexpr (std::is_same_v, hero_t>) + { + return std::make_shared(std::make_shared(hero)); + } + else if constexpr (std::is_same_v, hero_t>) + { + return std::make_shared(std::make_shared(hero)); + } + }, + hero); +} + +std::shared_ptr make_hero(const WeakHero& hero) noexcept +{ + return std::visit( + [](const auto& hero) noexcept { + using hero_t = std::decay_t; + + if constexpr (std::is_same_v, hero_t>) + { + return std::make_shared( + std::make_shared(hero.lock())); + } + else if constexpr (std::is_same_v, hero_t>) + { + return std::make_shared( + std::make_shared(hero.lock())); + } + }, + hero); +} + +} // namespace graphql::learn diff --git a/samples/star_wars/HeroData.h b/samples/learn/HeroData.h similarity index 67% rename from samples/star_wars/HeroData.h rename to samples/learn/HeroData.h index 849929ff..0681905a 100644 --- a/samples/star_wars/HeroData.h +++ b/samples/learn/HeroData.h @@ -17,6 +17,15 @@ class Human; using SharedHero = std::variant, std::shared_ptr>; using WeakHero = std::variant, std::weak_ptr>; +namespace object { + +class Character; + +} // namespace object + +std::shared_ptr make_hero(const SharedHero& hero) noexcept; +std::shared_ptr make_hero(const WeakHero& hero) noexcept; + } // namespace graphql::learn #endif // HERODATA_H diff --git a/samples/learn/HumanData.cpp b/samples/learn/HumanData.cpp new file mode 100644 index 00000000..4650cb94 --- /dev/null +++ b/samples/learn/HumanData.cpp @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "HumanData.h" + +#include "DroidData.h" + +namespace graphql::learn { + +Human::Human(std::string&& id, std::optional&& name, std::vector&& appearsIn, + std::optional&& homePlanet) noexcept + : id_ { std::move(id) } + , name_ { std::move(name) } + , appearsIn_ { std::move(appearsIn) } + , homePlanet_ { std::move(homePlanet) } +{ +} + +void Human::addFriends(std::vector friends) noexcept +{ + friends_.resize(friends.size()); + + std::transform(friends.begin(), + friends.end(), + friends_.begin(), + [](const auto& spFriend) noexcept { + return std::visit( + [](const auto& hero) noexcept { + return WeakHero { + std::weak_ptr::element_type> { hero } + }; + }, + spFriend); + }); +} + +const std::string& Human::getId() const noexcept +{ + return id_; +} + +const std::optional& Human::getName() const noexcept +{ + return name_; +} + +std::optional>> Human::getFriends() const noexcept +{ + std::vector> result(friends_.size()); + + std::transform(friends_.begin(), + friends_.end(), + result.begin(), + [](const auto& wpFriend) noexcept { + return make_hero(wpFriend); + }); + result.erase(std::remove(result.begin(), result.end(), std::shared_ptr {}), + result.end()); + + return result.empty() ? std::nullopt : std::make_optional(std::move(result)); +} + +std::optional>> Human::getAppearsIn() const noexcept +{ + std::vector> result(appearsIn_.size()); + + std::transform(appearsIn_.begin(), + appearsIn_.end(), + result.begin(), + [](const auto& entry) noexcept { + return std::make_optional(entry); + }); + + return result.empty() ? std::nullopt : std::make_optional(std::move(result)); +} + +const std::optional& Human::getHomePlanet() const noexcept +{ + return homePlanet_; +} + +} // namespace graphql::learn diff --git a/samples/learn/HumanData.h b/samples/learn/HumanData.h new file mode 100644 index 00000000..e29bd3b3 --- /dev/null +++ b/samples/learn/HumanData.h @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef HUMANDATA_H +#define HUMANDATA_H + +#include "HeroData.h" + +#include "HumanObject.h" + +namespace graphql::learn { + +class Human +{ +public: + explicit Human(std::string&& id, std::optional&& name, + std::vector&& appearsIn, std::optional&& homePlanet) noexcept; + + void addFriends(std::vector friends) noexcept; + + const std::string& getId() const noexcept; + const std::optional& getName() const noexcept; + std::optional>> getFriends() const noexcept; + std::optional>> getAppearsIn() const noexcept; + const std::optional& getHomePlanet() const noexcept; + +private: + const std::string id_; + const std::optional name_; + const std::vector appearsIn_; + const std::optional homePlanet_; + + std::vector friends_; +}; + +} // namespace graphql::learn + +#endif // HUMANDATA_H diff --git a/samples/learn/HumanObject.cpp b/samples/learn/HumanObject.cpp deleted file mode 100644 index 4769437c..00000000 --- a/samples/learn/HumanObject.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "StarWarsObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::learn { -namespace object { - -Human::Human() - : service::Object({ - "Character", - "Human" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(friends)gql"sv, [this](service::ResolverParams&& params) { return resolveFriends(std::move(params)); } }, - { R"gql(appearsIn)gql"sv, [this](service::ResolverParams&& params) { return resolveAppearsIn(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(homePlanet)gql"sv, [this](service::ResolverParams&& params) { return resolveHomePlanet(std::move(params)); } } - }) -{ -} - -service::FieldResult Human::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Human::getId is not implemented)ex"); -} - -std::future Human::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Human::getName(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Human::getName is not implemented)ex"); -} - -std::future Human::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> Human::getFriends(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Human::getFriends is not implemented)ex"); -} - -std::future Human::resolveFriends(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getFriends(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> Human::getAppearsIn(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Human::getAppearsIn is not implemented)ex"); -} - -std::future Human::resolveAppearsIn(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getAppearsIn(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Human::getHomePlanet(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Human::getHomePlanet is not implemented)ex"); -} - -std::future Human::resolveHomePlanet(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHomePlanet(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Human::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Human)gql" }, std::move(params)); -} - -} // namespace object - -void AddHumanDetails(std::shared_ptr typeHuman, const std::shared_ptr& schema) -{ - typeHuman->AddInterfaces({ - std::static_pointer_cast(schema->LookupType(R"gql(Character)gql"sv)) - }); - typeHuman->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(friends)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Character"))), - schema::Field::Make(R"gql(appearsIn)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Episode"))), - schema::Field::Make(R"gql(homePlanet)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); -} - -} // namespace graphql::learn diff --git a/samples/learn/HumanObject.h b/samples/learn/HumanObject.h deleted file mode 100644 index 3836df6a..00000000 --- a/samples/learn/HumanObject.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef HUMANOBJECT_H -#define HUMANOBJECT_H - -#include "StarWarsSchema.h" - -namespace graphql::learn::object { - -class Human - : public service::Object - , public Character -{ -protected: - explicit Human(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getName(service::FieldParams&& params) const override; - virtual service::FieldResult>>> getFriends(service::FieldParams&& params) const override; - virtual service::FieldResult>>> getAppearsIn(service::FieldParams&& params) const override; - virtual service::FieldResult> getHomePlanet(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveName(service::ResolverParams&& params); - std::future resolveFriends(service::ResolverParams&& params); - std::future resolveAppearsIn(service::ResolverParams&& params); - std::future resolveHomePlanet(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::learn::object - -#endif // HUMANOBJECT_H diff --git a/samples/star_wars/MutationData.cpp b/samples/learn/MutationData.cpp similarity index 69% rename from samples/star_wars/MutationData.cpp rename to samples/learn/MutationData.cpp index 0fa6e276..a9212d5b 100644 --- a/samples/star_wars/MutationData.cpp +++ b/samples/learn/MutationData.cpp @@ -9,15 +9,15 @@ Mutation::Mutation() noexcept { } -service::FieldResult> Mutation::applyCreateReview( - service::FieldParams&& params, Episode&& epArg, ReviewInput&& reviewArg) const +std::shared_ptr Mutation::applyCreateReview( + Episode epArg, ReviewInput&& reviewArg) noexcept { auto review = std::make_shared(reviewArg.stars, std::move(reviewArg.commentary)); // Save a copy of this review associated with this episode. reviews_[epArg].push_back(review); - return review; + return std::make_shared(std::move(review)); } } // namespace graphql::learn diff --git a/samples/star_wars/MutationData.h b/samples/learn/MutationData.h similarity index 63% rename from samples/star_wars/MutationData.h rename to samples/learn/MutationData.h index 4bb85a38..3b3fc9c0 100644 --- a/samples/star_wars/MutationData.h +++ b/samples/learn/MutationData.h @@ -12,18 +12,18 @@ namespace graphql::learn { -class Mutation : public object::Mutation +class Mutation { public: explicit Mutation() noexcept; - service::FieldResult> applyCreateReview( - service::FieldParams&& params, Episode&& epArg, ReviewInput&& reviewArg) const final; + std::shared_ptr applyCreateReview( + Episode epArg, ReviewInput&& reviewArg) noexcept; private: // This is just an example, the Mutation object probably shouldn't own a mutable store for the // reviews in a member variable. - mutable std::map>> reviews_; + std::map>> reviews_; }; } // namespace graphql::learn diff --git a/samples/learn/MutationObject.h b/samples/learn/MutationObject.h deleted file mode 100644 index 53f5b0a0..00000000 --- a/samples/learn/MutationObject.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef MUTATIONOBJECT_H -#define MUTATIONOBJECT_H - -#include "StarWarsSchema.h" - -namespace graphql::learn::object { - -class Mutation - : public service::Object -{ -protected: - explicit Mutation(); - -public: - virtual service::FieldResult> applyCreateReview(service::FieldParams&& params, Episode&& epArg, ReviewInput&& reviewArg) const; - -private: - std::future resolveCreateReview(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::learn::object - -#endif // MUTATIONOBJECT_H diff --git a/samples/learn/QueryData.cpp b/samples/learn/QueryData.cpp new file mode 100644 index 00000000..eb6dec9a --- /dev/null +++ b/samples/learn/QueryData.cpp @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "CharacterObject.h" + +#include "QueryData.h" + +namespace graphql::learn { + +Query::Query(std::map&& heroes, + std::map>&& humans, + std::map>&& droids) noexcept + : heroes_ { std::move(heroes) } + , humans_ { std::move(humans) } + , droids_ { std::move(droids) } +{ +} + +std::shared_ptr Query::getHero(std::optional episodeArg) const noexcept +{ + std::shared_ptr result; + const auto episode = episodeArg ? *episodeArg : Episode::NEW_HOPE; + + if (const auto itr = heroes_.find(episode); itr != heroes_.end()) + { + result = make_hero(itr->second); + } + + return result; +} + +std::shared_ptr Query::getHuman(const std::string& idArg) const noexcept +{ + std::shared_ptr result; + + if (const auto itr = humans_.find(idArg); itr != humans_.end()) + { + result = itr->second; + } + + return std::make_shared(std::move(result)); +} + +std::shared_ptr Query::getDroid(const std::string& idArg) const noexcept +{ + std::shared_ptr result; + + if (const auto itr = droids_.find(idArg); itr != droids_.end()) + { + result = itr->second; + } + + return std::make_shared(std::move(result)); +} + +} // namespace graphql::learn diff --git a/samples/learn/QueryData.h b/samples/learn/QueryData.h new file mode 100644 index 00000000..0552e65f --- /dev/null +++ b/samples/learn/QueryData.h @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef QUERYDATA_H +#define QUERYDATA_H + +#include "QueryObject.h" + +#include "DroidData.h" +#include "HumanData.h" + +namespace graphql::learn { + +class Query +{ +public: + explicit Query(std::map&& heroes, + std::map>&& humans, + std::map>&& droids) noexcept; + + std::shared_ptr getHero(std::optional episodeArg) const noexcept; + std::shared_ptr getHuman(const std::string& idArg) const noexcept; + std::shared_ptr getDroid(const std::string& idArg) const noexcept; + +private: + const std::map heroes_; + const std::map> humans_; + const std::map> droids_; +}; + +} // namespace graphql::learn + +#endif // QUERYDATA_H diff --git a/samples/learn/QueryObject.cpp b/samples/learn/QueryObject.cpp deleted file mode 100644 index 75e50c1b..00000000 --- a/samples/learn/QueryObject.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "StarWarsObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::learn { -namespace object { - -Query::Query() - : service::Object({ - "Query" - }, { - { R"gql(hero)gql"sv, [this](service::ResolverParams&& params) { return resolveHero(std::move(params)); } }, - { R"gql(droid)gql"sv, [this](service::ResolverParams&& params) { return resolveDroid(std::move(params)); } }, - { R"gql(human)gql"sv, [this](service::ResolverParams&& params) { return resolveHuman(std::move(params)); } }, - { R"gql(__type)gql"sv, [this](service::ResolverParams&& params) { return resolve_type(std::move(params)); } }, - { R"gql(__schema)gql"sv, [this](service::ResolverParams&& params) { return resolve_schema(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) - , _schema(GetSchema()) -{ -} - -service::FieldResult> Query::getHero(service::FieldParams&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getHero is not implemented)ex"); -} - -std::future Query::resolveHero(service::ResolverParams&& params) -{ - auto argEpisode = service::ModifiedArgument::require("episode", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHero(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argEpisode)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getHuman(service::FieldParams&&, response::StringType&&) const -{ - throw std::runtime_error(R"ex(Query::getHuman is not implemented)ex"); -} - -std::future Query::resolveHuman(service::ResolverParams&& params) -{ - auto argId = service::ModifiedArgument::require("id", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHuman(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getDroid(service::FieldParams&&, response::StringType&&) const -{ - throw std::runtime_error(R"ex(Query::getDroid is not implemented)ex"); -} - -std::future Query::resolveDroid(service::ResolverParams&& params) -{ - auto argId = service::ModifiedArgument::require("id", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDroid(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Query::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Query)gql" }, std::move(params)); -} - -std::future Query::resolve_schema(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(std::static_pointer_cast(std::make_shared(_schema)), std::move(params)); -} - -std::future Query::resolve_type(service::ResolverParams&& params) -{ - auto argName = service::ModifiedArgument::require("name", params.arguments); - const auto& baseType = _schema->LookupType(argName); - std::shared_ptr result { baseType ? std::make_shared(baseType) : nullptr }; - - return service::ModifiedResult::convert(result, std::move(params)); -} - -} // namespace object - -void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema) -{ - typeQuery->AddFields({ - schema::Field::Make(R"gql(hero)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Character"), { - schema::InputValue::Make(R"gql(episode)gql"sv, R"md()md"sv, schema->LookupType("Episode"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(human)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Human"), { - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(droid)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Droid"), { - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - }) - }); -} - -} // namespace graphql::learn diff --git a/samples/learn/QueryObject.h b/samples/learn/QueryObject.h deleted file mode 100644 index dc45c748..00000000 --- a/samples/learn/QueryObject.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef QUERYOBJECT_H -#define QUERYOBJECT_H - -#include "StarWarsSchema.h" - -namespace graphql::learn::object { - -class Query - : public service::Object -{ -protected: - explicit Query(); - -public: - virtual service::FieldResult> getHero(service::FieldParams&& params, std::optional&& episodeArg) const; - virtual service::FieldResult> getHuman(service::FieldParams&& params, response::StringType&& idArg) const; - virtual service::FieldResult> getDroid(service::FieldParams&& params, response::StringType&& idArg) const; - -private: - std::future resolveHero(service::ResolverParams&& params); - std::future resolveHuman(service::ResolverParams&& params); - std::future resolveDroid(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); - std::future resolve_schema(service::ResolverParams&& params); - std::future resolve_type(service::ResolverParams&& params); - - std::shared_ptr _schema; -}; - -} // namespace graphql::learn::object - -#endif // QUERYOBJECT_H diff --git a/samples/learn/ReviewData.cpp b/samples/learn/ReviewData.cpp new file mode 100644 index 00000000..276b3e0a --- /dev/null +++ b/samples/learn/ReviewData.cpp @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "ReviewData.h" + +namespace graphql::learn { + +Review::Review(int stars, std::optional&& commentary) noexcept + : stars_ { stars } + , commentary_ { std::move(commentary) } +{ +} + +int Review::getStars() const noexcept +{ + return stars_; +} + +const std::optional& Review::getCommentary() const noexcept +{ + return commentary_; +} + +} // namespace graphql::learn diff --git a/samples/learn/ReviewData.h b/samples/learn/ReviewData.h new file mode 100644 index 00000000..4d75959e --- /dev/null +++ b/samples/learn/ReviewData.h @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef REVIEWDATA_H +#define REVIEWDATA_H + +#include "ReviewObject.h" + +namespace graphql::learn { + +class Review +{ +public: + explicit Review(int stars, std::optional&& commentary) noexcept; + + int getStars() const noexcept; + const std::optional& getCommentary() const noexcept; + +private: + const int stars_; + const std::optional commentary_; +}; + +} // namespace graphql::learn + +#endif // REVIEWDATA_H diff --git a/samples/learn/ReviewObject.cpp b/samples/learn/ReviewObject.cpp deleted file mode 100644 index 82451ea8..00000000 --- a/samples/learn/ReviewObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "StarWarsObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::learn { -namespace object { - -Review::Review() - : service::Object({ - "Review" - }, { - { R"gql(stars)gql"sv, [this](service::ResolverParams&& params) { return resolveStars(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(commentary)gql"sv, [this](service::ResolverParams&& params) { return resolveCommentary(std::move(params)); } } - }) -{ -} - -service::FieldResult Review::getStars(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Review::getStars is not implemented)ex"); -} - -std::future Review::resolveStars(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getStars(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Review::getCommentary(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Review::getCommentary is not implemented)ex"); -} - -std::future Review::resolveCommentary(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCommentary(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Review::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Review)gql" }, std::move(params)); -} - -} // namespace object - -void AddReviewDetails(std::shared_ptr typeReview, const std::shared_ptr& schema) -{ - typeReview->AddFields({ - schema::Field::Make(R"gql(stars)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), - schema::Field::Make(R"gql(commentary)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); -} - -} // namespace graphql::learn diff --git a/samples/learn/ReviewObject.h b/samples/learn/ReviewObject.h deleted file mode 100644 index 7cb80abe..00000000 --- a/samples/learn/ReviewObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef REVIEWOBJECT_H -#define REVIEWOBJECT_H - -#include "StarWarsSchema.h" - -namespace graphql::learn::object { - -class Review - : public service::Object -{ -protected: - explicit Review(); - -public: - virtual service::FieldResult getStars(service::FieldParams&& params) const; - virtual service::FieldResult> getCommentary(service::FieldParams&& params) const; - -private: - std::future resolveStars(service::ResolverParams&& params); - std::future resolveCommentary(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::learn::object - -#endif // REVIEWOBJECT_H diff --git a/samples/star_wars/StarWarsData.cpp b/samples/learn/StarWarsData.cpp similarity index 88% rename from samples/star_wars/StarWarsData.cpp rename to samples/learn/StarWarsData.cpp index d5e8457d..57a89a99 100644 --- a/samples/star_wars/StarWarsData.cpp +++ b/samples/learn/StarWarsData.cpp @@ -9,8 +9,6 @@ #include "QueryData.h" #include "ReviewData.h" -#include "StarWarsObjects.h" - using namespace std::literals; namespace graphql::star_wars { @@ -99,17 +97,17 @@ std::shared_ptr GetService() noexcept { learn::Episode::JEDI, { artoo } }, }; - std::map> humans { - { luke->id(), luke }, - { vader->id(), vader }, - { han->id(), han }, - { leia->id(), leia }, - { tarkin->id(), tarkin }, + std::map> humans { + { luke->getId(), luke }, + { vader->getId(), vader }, + { han->getId(), han }, + { leia->getId(), leia }, + { tarkin->getId(), tarkin }, }; - std::map> droids { - { threepio->id(), threepio }, - { artoo->id(), artoo }, + std::map> droids { + { threepio->getId(), threepio }, + { artoo->getId(), artoo }, }; auto query = diff --git a/samples/star_wars/StarWarsData.h b/samples/learn/StarWarsData.h similarity index 100% rename from samples/star_wars/StarWarsData.h rename to samples/learn/StarWarsData.h diff --git a/samples/learn/StarWarsObjects.h b/samples/learn/StarWarsObjects.h deleted file mode 100644 index 80b7d28f..00000000 --- a/samples/learn/StarWarsObjects.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef STARWARSOBJECTS_H -#define STARWARSOBJECTS_H - -#include "StarWarsSchema.h" - -#include "HumanObject.h" -#include "DroidObject.h" -#include "QueryObject.h" -#include "ReviewObject.h" -#include "MutationObject.h" - -#endif // STARWARSOBJECTS_H diff --git a/samples/learn/StarWarsSchema.h b/samples/learn/StarWarsSchema.h deleted file mode 100644 index 1bc92081..00000000 --- a/samples/learn/StarWarsSchema.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef STARWARSSCHEMA_H -#define STARWARSSCHEMA_H - -#include "graphqlservice/internal/Schema.h" - -// Check if the library version is compatible with schemagen 3.6.0 -static_assert(graphql::internal::MajorVersion == 3, "regenerate with schemagen: major version mismatch"); -static_assert(graphql::internal::MinorVersion == 6, "regenerate with schemagen: minor version mismatch"); - -#include -#include -#include - -namespace graphql { -namespace learn { - -enum class Episode -{ - NEW_HOPE, - EMPIRE, - JEDI -}; - -struct ReviewInput -{ - response::IntType stars; - std::optional commentary; -}; - -namespace object { - -class Human; -class Droid; -class Query; -class Review; -class Mutation; - -} // namespace object - -struct Character -{ - virtual service::FieldResult getId(service::FieldParams&& params) const = 0; - virtual service::FieldResult> getName(service::FieldParams&& params) const = 0; - virtual service::FieldResult>>> getFriends(service::FieldParams&& params) const = 0; - virtual service::FieldResult>>> getAppearsIn(service::FieldParams&& params) const = 0; -}; - -class Operations - : public service::Request -{ -public: - explicit Operations(std::shared_ptr query, std::shared_ptr mutation); - -private: - std::shared_ptr _query; - std::shared_ptr _mutation; -}; - -void AddHumanDetails(std::shared_ptr typeHuman, const std::shared_ptr& schema); -void AddDroidDetails(std::shared_ptr typeDroid, const std::shared_ptr& schema); -void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema); -void AddReviewDetails(std::shared_ptr typeReview, const std::shared_ptr& schema); -void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema); - -std::shared_ptr GetSchema(); - -} // namespace learn -} // namespace graphql - -#endif // STARWARSSCHEMA_H diff --git a/samples/star_wars/sample.cpp b/samples/learn/sample.cpp similarity index 82% rename from samples/star_wars/sample.cpp rename to samples/learn/sample.cpp index d95da7a0..954916c1 100644 --- a/samples/star_wars/sample.cpp +++ b/samples/learn/sample.cpp @@ -43,12 +43,8 @@ int main(int argc, char** argv) std::cout << "Executing query..." << std::endl; - std::cout << response::toJSON(service - ->resolve(nullptr, - query, - ((argc > 2) ? argv[2] : ""), - response::Value(response::Type::Map)) - .get()) + std::cout << response::toJSON( + service->resolve({ query, ((argc > 2) ? argv[2] : "") }).get()) << std::endl; } catch (const std::runtime_error& ex) diff --git a/samples/learn/schema/CMakeLists.txt b/samples/learn/schema/CMakeLists.txt new file mode 100644 index 00000000..2cab0cc0 --- /dev/null +++ b/samples/learn/schema/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +# Normally this would be handled by find_package(cppgraphqlgen CONFIG). +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/cppgraphqlgen-functions.cmake) + +if(GRAPHQL_UPDATE_SAMPLES) + update_graphql_schema_files(learn schema.learn.graphql StarWars learn) +endif() + +add_graphql_schema_target(learn) diff --git a/samples/learn/schema/CharacterObject.cpp b/samples/learn/schema/CharacterObject.cpp new file mode 100644 index 00000000..3af5cfcb --- /dev/null +++ b/samples/learn/schema/CharacterObject.cpp @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "CharacterObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::learn { +namespace object { + +Character::Character(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void Character::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Character::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddCharacterDetails(const std::shared_ptr& typeCharacter, const std::shared_ptr& schema) +{ + typeCharacter->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(friends)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Character)gql"sv))), + schema::Field::Make(R"gql(appearsIn)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Episode)gql"sv))) + }); +} + +} // namespace graphql::learn diff --git a/samples/learn/schema/CharacterObject.h b/samples/learn/schema/CharacterObject.h new file mode 100644 index 00000000..d69e63b7 --- /dev/null +++ b/samples/learn/schema/CharacterObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef CHARACTEROBJECT_H +#define CHARACTEROBJECT_H + +#include "StarWarsSchema.h" + +namespace graphql::learn::object { + +class Character + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + Character(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Character(std::shared_ptr pimpl) noexcept + : Character { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "Character is not implemented"); + } +}; + +} // namespace graphql::learn::object + +#endif // CHARACTEROBJECT_H diff --git a/samples/learn/schema/DroidObject.cpp b/samples/learn/schema/DroidObject.cpp new file mode 100644 index 00000000..16fb273c --- /dev/null +++ b/samples/learn/schema/DroidObject.cpp @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "DroidObject.h" +#include "CharacterObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::learn { +namespace object { + +Droid::Droid(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Droid::getTypeNames() const noexcept +{ + return { + R"gql(Character)gql"sv, + R"gql(Droid)gql"sv + }; +} + +service::ResolverMap Droid::getResolvers() const noexcept +{ + return { + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(friends)gql"sv, [this](service::ResolverParams&& params) { return resolveFriends(std::move(params)); } }, + { R"gql(appearsIn)gql"sv, [this](service::ResolverParams&& params) { return resolveAppearsIn(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(primaryFunction)gql"sv, [this](service::ResolverParams&& params) { return resolvePrimaryFunction(std::move(params)); } } + }; +} + +void Droid::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Droid::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Droid::resolveId(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Droid::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Droid::resolveFriends(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getFriends(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Droid::resolveAppearsIn(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getAppearsIn(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Droid::resolvePrimaryFunction(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getPrimaryFunction(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Droid::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Droid)gql" }, std::move(params)); +} + +} // namespace object + +void AddDroidDetails(const std::shared_ptr& typeDroid, const std::shared_ptr& schema) +{ + typeDroid->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Character)gql"sv)) + }); + typeDroid->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(friends)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Character)gql"sv))), + schema::Field::Make(R"gql(appearsIn)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Episode)gql"sv))), + schema::Field::Make(R"gql(primaryFunction)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::learn diff --git a/samples/learn/schema/DroidObject.h b/samples/learn/schema/DroidObject.h new file mode 100644 index 00000000..748b5d0e --- /dev/null +++ b/samples/learn/schema/DroidObject.h @@ -0,0 +1,246 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef DROIDOBJECT_H +#define DROIDOBJECT_H + +#include "StarWarsSchema.h" + +namespace graphql::learn::object { +namespace implements { + +template +concept DroidIs = std::is_same_v; + +} // namespace implements + +namespace methods::DroidHas { + +template +concept getIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getId(std::move(params)) } }; +}; + +template +concept getId = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getId() } }; +}; + +template +concept getNameWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getName(std::move(params)) } }; +}; + +template +concept getName = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getName() } }; +}; + +template +concept getFriendsWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject>>> { impl.getFriends(std::move(params)) } }; +}; + +template +concept getFriends = requires (TImpl impl) +{ + { service::AwaitableObject>>> { impl.getFriends() } }; +}; + +template +concept getAppearsInWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar>>> { impl.getAppearsIn(std::move(params)) } }; +}; + +template +concept getAppearsIn = requires (TImpl impl) +{ + { service::AwaitableScalar>>> { impl.getAppearsIn() } }; +}; + +template +concept getPrimaryFunctionWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getPrimaryFunction(std::move(params)) } }; +}; + +template +concept getPrimaryFunction = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getPrimaryFunction() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::DroidHas + +class Droid + : public service::Object +{ +private: + service::AwaitableResolver resolveId(service::ResolverParams&& params) const; + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveFriends(service::ResolverParams&& params) const; + service::AwaitableResolver resolveAppearsIn(service::ResolverParams&& params) const; + service::AwaitableResolver resolvePrimaryFunction(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getId(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getName(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>>> getFriends(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar>>> getAppearsIn(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getPrimaryFunction(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getId(service::FieldParams&& params) const final + { + if constexpr (methods::DroidHas::getIdWithParams) + { + return { _pimpl->getId(std::move(params)) }; + } + else + { + static_assert(methods::DroidHas::getId, R"msg(Droid::getId is not implemented)msg"); + return { _pimpl->getId() }; + } + } + + service::AwaitableScalar> getName(service::FieldParams&& params) const final + { + if constexpr (methods::DroidHas::getNameWithParams) + { + return { _pimpl->getName(std::move(params)) }; + } + else + { + static_assert(methods::DroidHas::getName, R"msg(Droid::getName is not implemented)msg"); + return { _pimpl->getName() }; + } + } + + service::AwaitableObject>>> getFriends(service::FieldParams&& params) const final + { + if constexpr (methods::DroidHas::getFriendsWithParams) + { + return { _pimpl->getFriends(std::move(params)) }; + } + else + { + static_assert(methods::DroidHas::getFriends, R"msg(Droid::getFriends is not implemented)msg"); + return { _pimpl->getFriends() }; + } + } + + service::AwaitableScalar>>> getAppearsIn(service::FieldParams&& params) const final + { + if constexpr (methods::DroidHas::getAppearsInWithParams) + { + return { _pimpl->getAppearsIn(std::move(params)) }; + } + else + { + static_assert(methods::DroidHas::getAppearsIn, R"msg(Droid::getAppearsIn is not implemented)msg"); + return { _pimpl->getAppearsIn() }; + } + } + + service::AwaitableScalar> getPrimaryFunction(service::FieldParams&& params) const final + { + if constexpr (methods::DroidHas::getPrimaryFunctionWithParams) + { + return { _pimpl->getPrimaryFunction(std::move(params)) }; + } + else + { + static_assert(methods::DroidHas::getPrimaryFunction, R"msg(Droid::getPrimaryFunction is not implemented)msg"); + return { _pimpl->getPrimaryFunction() }; + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::DroidHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::DroidHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Droid(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Character; + + template + static constexpr bool implements() noexcept + { + return implements::DroidIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Droid(std::shared_ptr pimpl) noexcept + : Droid { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::learn::object + +#endif // DROIDOBJECT_H diff --git a/samples/learn/schema/HumanObject.cpp b/samples/learn/schema/HumanObject.cpp new file mode 100644 index 00000000..0bf1cbbd --- /dev/null +++ b/samples/learn/schema/HumanObject.cpp @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "HumanObject.h" +#include "CharacterObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::learn { +namespace object { + +Human::Human(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Human::getTypeNames() const noexcept +{ + return { + R"gql(Character)gql"sv, + R"gql(Human)gql"sv + }; +} + +service::ResolverMap Human::getResolvers() const noexcept +{ + return { + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(friends)gql"sv, [this](service::ResolverParams&& params) { return resolveFriends(std::move(params)); } }, + { R"gql(appearsIn)gql"sv, [this](service::ResolverParams&& params) { return resolveAppearsIn(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(homePlanet)gql"sv, [this](service::ResolverParams&& params) { return resolveHomePlanet(std::move(params)); } } + }; +} + +void Human::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Human::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Human::resolveId(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Human::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Human::resolveFriends(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getFriends(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Human::resolveAppearsIn(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getAppearsIn(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Human::resolveHomePlanet(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getHomePlanet(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Human::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Human)gql" }, std::move(params)); +} + +} // namespace object + +void AddHumanDetails(const std::shared_ptr& typeHuman, const std::shared_ptr& schema) +{ + typeHuman->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Character)gql"sv)) + }); + typeHuman->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(friends)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Character)gql"sv))), + schema::Field::Make(R"gql(appearsIn)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Episode)gql"sv))), + schema::Field::Make(R"gql(homePlanet)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::learn diff --git a/samples/learn/schema/HumanObject.h b/samples/learn/schema/HumanObject.h new file mode 100644 index 00000000..11eef4e0 --- /dev/null +++ b/samples/learn/schema/HumanObject.h @@ -0,0 +1,246 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef HUMANOBJECT_H +#define HUMANOBJECT_H + +#include "StarWarsSchema.h" + +namespace graphql::learn::object { +namespace implements { + +template +concept HumanIs = std::is_same_v; + +} // namespace implements + +namespace methods::HumanHas { + +template +concept getIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getId(std::move(params)) } }; +}; + +template +concept getId = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getId() } }; +}; + +template +concept getNameWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getName(std::move(params)) } }; +}; + +template +concept getName = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getName() } }; +}; + +template +concept getFriendsWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject>>> { impl.getFriends(std::move(params)) } }; +}; + +template +concept getFriends = requires (TImpl impl) +{ + { service::AwaitableObject>>> { impl.getFriends() } }; +}; + +template +concept getAppearsInWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar>>> { impl.getAppearsIn(std::move(params)) } }; +}; + +template +concept getAppearsIn = requires (TImpl impl) +{ + { service::AwaitableScalar>>> { impl.getAppearsIn() } }; +}; + +template +concept getHomePlanetWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getHomePlanet(std::move(params)) } }; +}; + +template +concept getHomePlanet = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getHomePlanet() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::HumanHas + +class Human + : public service::Object +{ +private: + service::AwaitableResolver resolveId(service::ResolverParams&& params) const; + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveFriends(service::ResolverParams&& params) const; + service::AwaitableResolver resolveAppearsIn(service::ResolverParams&& params) const; + service::AwaitableResolver resolveHomePlanet(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getId(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getName(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>>> getFriends(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar>>> getAppearsIn(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getHomePlanet(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getId(service::FieldParams&& params) const final + { + if constexpr (methods::HumanHas::getIdWithParams) + { + return { _pimpl->getId(std::move(params)) }; + } + else + { + static_assert(methods::HumanHas::getId, R"msg(Human::getId is not implemented)msg"); + return { _pimpl->getId() }; + } + } + + service::AwaitableScalar> getName(service::FieldParams&& params) const final + { + if constexpr (methods::HumanHas::getNameWithParams) + { + return { _pimpl->getName(std::move(params)) }; + } + else + { + static_assert(methods::HumanHas::getName, R"msg(Human::getName is not implemented)msg"); + return { _pimpl->getName() }; + } + } + + service::AwaitableObject>>> getFriends(service::FieldParams&& params) const final + { + if constexpr (methods::HumanHas::getFriendsWithParams) + { + return { _pimpl->getFriends(std::move(params)) }; + } + else + { + static_assert(methods::HumanHas::getFriends, R"msg(Human::getFriends is not implemented)msg"); + return { _pimpl->getFriends() }; + } + } + + service::AwaitableScalar>>> getAppearsIn(service::FieldParams&& params) const final + { + if constexpr (methods::HumanHas::getAppearsInWithParams) + { + return { _pimpl->getAppearsIn(std::move(params)) }; + } + else + { + static_assert(methods::HumanHas::getAppearsIn, R"msg(Human::getAppearsIn is not implemented)msg"); + return { _pimpl->getAppearsIn() }; + } + } + + service::AwaitableScalar> getHomePlanet(service::FieldParams&& params) const final + { + if constexpr (methods::HumanHas::getHomePlanetWithParams) + { + return { _pimpl->getHomePlanet(std::move(params)) }; + } + else + { + static_assert(methods::HumanHas::getHomePlanet, R"msg(Human::getHomePlanet is not implemented)msg"); + return { _pimpl->getHomePlanet() }; + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::HumanHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::HumanHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Human(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Character; + + template + static constexpr bool implements() noexcept + { + return implements::HumanIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Human(std::shared_ptr pimpl) noexcept + : Human { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::learn::object + +#endif // HUMANOBJECT_H diff --git a/samples/learn/MutationObject.cpp b/samples/learn/schema/MutationObject.cpp similarity index 51% rename from samples/learn/MutationObject.cpp rename to samples/learn/schema/MutationObject.cpp index 56582b09..874c1218 100644 --- a/samples/learn/MutationObject.cpp +++ b/samples/learn/schema/MutationObject.cpp @@ -3,9 +3,12 @@ // WARNING! Do not edit this file manually, your changes will be overwritten. -#include "StarWarsObjects.h" +#include "MutationObject.h" +#include "ReviewObject.h" -#include "graphqlservice/introspection/Introspection.h" +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" #include #include @@ -18,46 +21,62 @@ using namespace std::literals; namespace graphql::learn { namespace object { -Mutation::Mutation() - : service::Object({ - "Mutation" - }, { +Mutation::Mutation(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Mutation::getTypeNames() const noexcept +{ + return { + R"gql(Mutation)gql"sv + }; +} + +service::ResolverMap Mutation::getResolvers() const noexcept +{ + return { { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, { R"gql(createReview)gql"sv, [this](service::ResolverParams&& params) { return resolveCreateReview(std::move(params)); } } - }) + }; +} + +void Mutation::beginSelectionSet(const service::SelectionSetParams& params) const { + _pimpl->beginSelectionSet(params); } -service::FieldResult> Mutation::applyCreateReview(service::FieldParams&&, Episode&&, ReviewInput&&) const +void Mutation::endSelectionSet(const service::SelectionSetParams& params) const { - throw std::runtime_error(R"ex(Mutation::applyCreateReview is not implemented)ex"); + _pimpl->endSelectionSet(params); } -std::future Mutation::resolveCreateReview(service::ResolverParams&& params) +service::AwaitableResolver Mutation::resolveCreateReview(service::ResolverParams&& params) const { auto argEp = service::ModifiedArgument::require("ep", params.arguments); auto argReview = service::ModifiedArgument::require("review", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = applyCreateReview(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argEp), std::move(argReview)); + auto result = _pimpl->applyCreateReview(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argEp), std::move(argReview)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Mutation::resolve_typename(service::ResolverParams&& params) +service::AwaitableResolver Mutation::resolve_typename(service::ResolverParams&& params) const { - return service::ModifiedResult::convert(response::StringType{ R"gql(Mutation)gql" }, std::move(params)); + return service::ModifiedResult::convert(std::string{ R"gql(Mutation)gql" }, std::move(params)); } } // namespace object -void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema) +void AddMutationDetails(const std::shared_ptr& typeMutation, const std::shared_ptr& schema) { typeMutation->AddFields({ - schema::Field::Make(R"gql(createReview)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Review")), { - schema::InputValue::Make(R"gql(ep)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Episode")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(review)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ReviewInput")), R"gql()gql"sv) + schema::Field::Make(R"gql(createReview)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Review)gql"sv)), { + schema::InputValue::Make(R"gql(ep)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Episode)gql"sv)), R"gql()gql"sv), + schema::InputValue::Make(R"gql(review)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ReviewInput)gql"sv)), R"gql()gql"sv) }) }); } diff --git a/samples/learn/schema/MutationObject.h b/samples/learn/schema/MutationObject.h new file mode 100644 index 00000000..f4fc93a6 --- /dev/null +++ b/samples/learn/schema/MutationObject.h @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef MUTATIONOBJECT_H +#define MUTATIONOBJECT_H + +#include "StarWarsSchema.h" + +namespace graphql::learn::object { +namespace methods::MutationHas { + +template +concept applyCreateReviewWithParams = requires (TImpl impl, service::FieldParams params, Episode epArg, ReviewInput reviewArg) +{ + { service::AwaitableObject> { impl.applyCreateReview(std::move(params), std::move(epArg), std::move(reviewArg)) } }; +}; + +template +concept applyCreateReview = requires (TImpl impl, Episode epArg, ReviewInput reviewArg) +{ + { service::AwaitableObject> { impl.applyCreateReview(std::move(epArg), std::move(reviewArg)) } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::MutationHas + +class Mutation + : public service::Object +{ +private: + service::AwaitableResolver resolveCreateReview(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> applyCreateReview(service::FieldParams&& params, Episode&& epArg, ReviewInput&& reviewArg) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> applyCreateReview(service::FieldParams&& params, Episode&& epArg, ReviewInput&& reviewArg) const final + { + if constexpr (methods::MutationHas::applyCreateReviewWithParams) + { + return { _pimpl->applyCreateReview(std::move(params), std::move(epArg), std::move(reviewArg)) }; + } + else + { + static_assert(methods::MutationHas::applyCreateReview, R"msg(Mutation::applyCreateReview is not implemented)msg"); + return { _pimpl->applyCreateReview(std::move(epArg), std::move(reviewArg)) }; + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MutationHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MutationHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Mutation(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Mutation(std::shared_ptr pimpl) noexcept + : Mutation { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::learn::object + +#endif // MUTATIONOBJECT_H diff --git a/samples/learn/schema/QueryObject.cpp b/samples/learn/schema/QueryObject.cpp new file mode 100644 index 00000000..5b822b0f --- /dev/null +++ b/samples/learn/schema/QueryObject.cpp @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "QueryObject.h" +#include "CharacterObject.h" +#include "HumanObject.h" +#include "DroidObject.h" + +#include "graphqlservice/internal/Introspection.h" + +#include "graphqlservice/introspection/SchemaObject.h" +#include "graphqlservice/introspection/TypeObject.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::learn { +namespace object { + +Query::Query(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _schema { GetSchema() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Query::getTypeNames() const noexcept +{ + return { + R"gql(Query)gql"sv + }; +} + +service::ResolverMap Query::getResolvers() const noexcept +{ + return { + { R"gql(hero)gql"sv, [this](service::ResolverParams&& params) { return resolveHero(std::move(params)); } }, + { R"gql(droid)gql"sv, [this](service::ResolverParams&& params) { return resolveDroid(std::move(params)); } }, + { R"gql(human)gql"sv, [this](service::ResolverParams&& params) { return resolveHuman(std::move(params)); } }, + { R"gql(__type)gql"sv, [this](service::ResolverParams&& params) { return resolve_type(std::move(params)); } }, + { R"gql(__schema)gql"sv, [this](service::ResolverParams&& params) { return resolve_schema(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void Query::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Query::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Query::resolveHero(service::ResolverParams&& params) const +{ + auto argEpisode = service::ModifiedArgument::require("episode", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getHero(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argEpisode)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Query::resolveHuman(service::ResolverParams&& params) const +{ + auto argId = service::ModifiedArgument::require("id", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getHuman(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Query::resolveDroid(service::ResolverParams&& params) const +{ + auto argId = service::ModifiedArgument::require("id", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getDroid(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Query::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Query)gql" }, std::move(params)); +} + +service::AwaitableResolver Query::resolve_schema(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::static_pointer_cast(std::make_shared(std::make_shared(_schema))), std::move(params)); +} + +service::AwaitableResolver Query::resolve_type(service::ResolverParams&& params) const +{ + auto argName = service::ModifiedArgument::require("name", params.arguments); + const auto& baseType = _schema->LookupType(argName); + std::shared_ptr result { baseType ? std::make_shared(std::make_shared(baseType)) : nullptr }; + + return service::ModifiedResult::convert(result, std::move(params)); +} + +} // namespace object + +void AddQueryDetails(const std::shared_ptr& typeQuery, const std::shared_ptr& schema) +{ + typeQuery->AddFields({ + schema::Field::Make(R"gql(hero)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Character)gql"sv), { + schema::InputValue::Make(R"gql(episode)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Episode)gql"sv), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(human)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Human)gql"sv), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(droid)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Droid)gql"sv), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }) + }); +} + +} // namespace graphql::learn diff --git a/samples/learn/schema/QueryObject.h b/samples/learn/schema/QueryObject.h new file mode 100644 index 00000000..fba68923 --- /dev/null +++ b/samples/learn/schema/QueryObject.h @@ -0,0 +1,180 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef QUERYOBJECT_H +#define QUERYOBJECT_H + +#include "StarWarsSchema.h" + +namespace graphql::learn::object { +namespace methods::QueryHas { + +template +concept getHeroWithParams = requires (TImpl impl, service::FieldParams params, std::optional episodeArg) +{ + { service::AwaitableObject> { impl.getHero(std::move(params), std::move(episodeArg)) } }; +}; + +template +concept getHero = requires (TImpl impl, std::optional episodeArg) +{ + { service::AwaitableObject> { impl.getHero(std::move(episodeArg)) } }; +}; + +template +concept getHumanWithParams = requires (TImpl impl, service::FieldParams params, std::string idArg) +{ + { service::AwaitableObject> { impl.getHuman(std::move(params), std::move(idArg)) } }; +}; + +template +concept getHuman = requires (TImpl impl, std::string idArg) +{ + { service::AwaitableObject> { impl.getHuman(std::move(idArg)) } }; +}; + +template +concept getDroidWithParams = requires (TImpl impl, service::FieldParams params, std::string idArg) +{ + { service::AwaitableObject> { impl.getDroid(std::move(params), std::move(idArg)) } }; +}; + +template +concept getDroid = requires (TImpl impl, std::string idArg) +{ + { service::AwaitableObject> { impl.getDroid(std::move(idArg)) } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::QueryHas + +class Query + : public service::Object +{ +private: + service::AwaitableResolver resolveHero(service::ResolverParams&& params) const; + service::AwaitableResolver resolveHuman(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDroid(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + service::AwaitableResolver resolve_schema(service::ResolverParams&& params) const; + service::AwaitableResolver resolve_type(service::ResolverParams&& params) const; + + std::shared_ptr _schema; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getHero(service::FieldParams&& params, std::optional&& episodeArg) const = 0; + virtual service::AwaitableObject> getHuman(service::FieldParams&& params, std::string&& idArg) const = 0; + virtual service::AwaitableObject> getDroid(service::FieldParams&& params, std::string&& idArg) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getHero(service::FieldParams&& params, std::optional&& episodeArg) const final + { + if constexpr (methods::QueryHas::getHeroWithParams) + { + return { _pimpl->getHero(std::move(params), std::move(episodeArg)) }; + } + else + { + static_assert(methods::QueryHas::getHero, R"msg(Query::getHero is not implemented)msg"); + return { _pimpl->getHero(std::move(episodeArg)) }; + } + } + + service::AwaitableObject> getHuman(service::FieldParams&& params, std::string&& idArg) const final + { + if constexpr (methods::QueryHas::getHumanWithParams) + { + return { _pimpl->getHuman(std::move(params), std::move(idArg)) }; + } + else + { + static_assert(methods::QueryHas::getHuman, R"msg(Query::getHuman is not implemented)msg"); + return { _pimpl->getHuman(std::move(idArg)) }; + } + } + + service::AwaitableObject> getDroid(service::FieldParams&& params, std::string&& idArg) const final + { + if constexpr (methods::QueryHas::getDroidWithParams) + { + return { _pimpl->getDroid(std::move(params), std::move(idArg)) }; + } + else + { + static_assert(methods::QueryHas::getDroid, R"msg(Query::getDroid is not implemented)msg"); + return { _pimpl->getDroid(std::move(idArg)) }; + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::QueryHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::QueryHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Query(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Query(std::shared_ptr pimpl) noexcept + : Query { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::learn::object + +#endif // QUERYOBJECT_H diff --git a/samples/learn/schema/ReviewObject.cpp b/samples/learn/schema/ReviewObject.cpp new file mode 100644 index 00000000..3c6fc43e --- /dev/null +++ b/samples/learn/schema/ReviewObject.cpp @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "ReviewObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::learn { +namespace object { + +Review::Review(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Review::getTypeNames() const noexcept +{ + return { + R"gql(Review)gql"sv + }; +} + +service::ResolverMap Review::getResolvers() const noexcept +{ + return { + { R"gql(stars)gql"sv, [this](service::ResolverParams&& params) { return resolveStars(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(commentary)gql"sv, [this](service::ResolverParams&& params) { return resolveCommentary(std::move(params)); } } + }; +} + +void Review::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Review::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Review::resolveStars(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getStars(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Review::resolveCommentary(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getCommentary(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Review::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Review)gql" }, std::move(params)); +} + +} // namespace object + +void AddReviewDetails(const std::shared_ptr& typeReview, const std::shared_ptr& schema) +{ + typeReview->AddFields({ + schema::Field::Make(R"gql(stars)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv))), + schema::Field::Make(R"gql(commentary)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::learn diff --git a/samples/learn/schema/ReviewObject.h b/samples/learn/schema/ReviewObject.h new file mode 100644 index 00000000..e47228e7 --- /dev/null +++ b/samples/learn/schema/ReviewObject.h @@ -0,0 +1,149 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef REVIEWOBJECT_H +#define REVIEWOBJECT_H + +#include "StarWarsSchema.h" + +namespace graphql::learn::object { +namespace methods::ReviewHas { + +template +concept getStarsWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getStars(std::move(params)) } }; +}; + +template +concept getStars = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getStars() } }; +}; + +template +concept getCommentaryWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getCommentary(std::move(params)) } }; +}; + +template +concept getCommentary = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getCommentary() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::ReviewHas + +class Review + : public service::Object +{ +private: + service::AwaitableResolver resolveStars(service::ResolverParams&& params) const; + service::AwaitableResolver resolveCommentary(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getStars(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getCommentary(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getStars(service::FieldParams&& params) const final + { + if constexpr (methods::ReviewHas::getStarsWithParams) + { + return { _pimpl->getStars(std::move(params)) }; + } + else + { + static_assert(methods::ReviewHas::getStars, R"msg(Review::getStars is not implemented)msg"); + return { _pimpl->getStars() }; + } + } + + service::AwaitableScalar> getCommentary(service::FieldParams&& params) const final + { + if constexpr (methods::ReviewHas::getCommentaryWithParams) + { + return { _pimpl->getCommentary(std::move(params)) }; + } + else + { + static_assert(methods::ReviewHas::getCommentary, R"msg(Review::getCommentary is not implemented)msg"); + return { _pimpl->getCommentary() }; + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::ReviewHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::ReviewHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Review(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Review(std::shared_ptr pimpl) noexcept + : Review { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::learn::object + +#endif // REVIEWOBJECT_H diff --git a/samples/learn/StarWarsSchema.cpp b/samples/learn/schema/StarWarsSchema.cpp similarity index 70% rename from samples/learn/StarWarsSchema.cpp rename to samples/learn/schema/StarWarsSchema.cpp index 25e1b8ad..f99c4fa8 100644 --- a/samples/learn/StarWarsSchema.cpp +++ b/samples/learn/schema/StarWarsSchema.cpp @@ -3,9 +3,12 @@ // WARNING! Do not edit this file manually, your changes will be overwritten. -#include "StarWarsObjects.h" +#include "QueryObject.h" +#include "MutationObject.h" -#include "graphqlservice/introspection/Introspection.h" +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" #include #include @@ -22,9 +25,9 @@ namespace graphql { namespace service { static const std::array s_namesEpisode = { - "NEW_HOPE"sv, - "EMPIRE"sv, - "JEDI"sv + R"gql(NEW_HOPE)gql"sv, + R"gql(EMPIRE)gql"sv, + R"gql(JEDI)gql"sv }; template <> @@ -32,38 +35,54 @@ learn::Episode ModifiedArgument::convert(const response::Value& { if (!value.maybe_enum()) { - throw service::schema_exception { { "not a valid Episode value" } }; + throw service::schema_exception { { R"ex(not a valid Episode value)ex" } }; } - const auto itr = std::find(s_namesEpisode.cbegin(), s_namesEpisode.cend(), value.get()); + const auto itr = std::find(s_namesEpisode.cbegin(), s_namesEpisode.cend(), value.get()); if (itr == s_namesEpisode.cend()) { - throw service::schema_exception { { "not a valid Episode value" } }; + throw service::schema_exception { { R"ex(not a valid Episode value)ex" } }; } return static_cast(itr - s_namesEpisode.cbegin()); } template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) +service::AwaitableResolver ModifiedResult::convert(service::AwaitableScalar result, ResolverParams params) { return resolve(std::move(result), std::move(params), [](learn::Episode value, const ResolverParams&) { response::Value result(response::Type::EnumValue); - result.set(response::StringType { s_namesEpisode[static_cast(value)] }); + result.set(std::string { s_namesEpisode[static_cast(value)] }); return result; }); } +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid Episode value)ex" } }; + } + + const auto itr = std::find(s_namesEpisode.cbegin(), s_namesEpisode.cend(), value.get()); + + if (itr == s_namesEpisode.cend()) + { + throw service::schema_exception { { R"ex(not a valid Episode value)ex" } }; + } +} + template <> learn::ReviewInput ModifiedArgument::convert(const response::Value& value) { - auto valueStars = service::ModifiedArgument::require("stars", value); - auto valueCommentary = service::ModifiedArgument::require("commentary", value); + auto valueStars = service::ModifiedArgument::require("stars", value); + auto valueCommentary = service::ModifiedArgument::require("commentary", value); return { std::move(valueStars), @@ -93,15 +112,15 @@ void AddTypesToSchema(const std::shared_ptr& schema) schema->AddType(R"gql(ReviewInput)gql"sv, typeReviewInput); auto typeCharacter = schema::InterfaceType::Make(R"gql(Character)gql"sv, R"md()md"sv); schema->AddType(R"gql(Character)gql"sv, typeCharacter); - auto typeHuman = schema::ObjectType::Make(R"gql(Human)gql"sv, R"md()md"); + auto typeHuman = schema::ObjectType::Make(R"gql(Human)gql"sv, R"md()md"sv); schema->AddType(R"gql(Human)gql"sv, typeHuman); - auto typeDroid = schema::ObjectType::Make(R"gql(Droid)gql"sv, R"md()md"); + auto typeDroid = schema::ObjectType::Make(R"gql(Droid)gql"sv, R"md()md"sv); schema->AddType(R"gql(Droid)gql"sv, typeDroid); - auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md()md"); + auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md()md"sv); schema->AddType(R"gql(Query)gql"sv, typeQuery); - auto typeReview = schema::ObjectType::Make(R"gql(Review)gql"sv, R"md()md"); + auto typeReview = schema::ObjectType::Make(R"gql(Review)gql"sv, R"md()md"sv); schema->AddType(R"gql(Review)gql"sv, typeReview); - auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"); + auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"sv); schema->AddType(R"gql(Mutation)gql"sv, typeMutation); typeEpisode->AddEnumValues({ @@ -111,16 +130,11 @@ void AddTypesToSchema(const std::shared_ptr& schema) }); typeReviewInput->AddInputValues({ - schema::InputValue::Make(R"gql(stars)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(commentary)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) + schema::InputValue::Make(R"gql(stars)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv)), R"gql()gql"sv), + schema::InputValue::Make(R"gql(commentary)gql"sv, R"md()md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql()gql"sv) }); - typeCharacter->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(friends)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Character"))), - schema::Field::Make(R"gql(appearsIn)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Episode"))) - }); + AddCharacterDetails(typeCharacter, schema); AddHumanDetails(typeHuman, schema); AddDroidDetails(typeDroid, schema); @@ -139,7 +153,7 @@ std::shared_ptr GetSchema() if (!schema) { - schema = std::make_shared(false); + schema = std::make_shared(false, R"md()md"sv); introspection::AddTypesToSchema(schema); AddTypesToSchema(schema); s_wpSchema = schema; diff --git a/samples/learn/schema/StarWarsSchema.h b/samples/learn/schema/StarWarsSchema.h new file mode 100644 index 00000000..59ac67bf --- /dev/null +++ b/samples/learn/schema/StarWarsSchema.h @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef STARWARSSCHEMA_H +#define STARWARSSCHEMA_H + +#include "graphqlservice/internal/Schema.h" + +// Check if the library version is compatible with schemagen 4.0.0 +static_assert(graphql::internal::MajorVersion == 4, "regenerate with schemagen: major version mismatch"); +static_assert(graphql::internal::MinorVersion == 0, "regenerate with schemagen: minor version mismatch"); + +#include +#include +#include + +namespace graphql { +namespace learn { + +enum class Episode +{ + NEW_HOPE, + EMPIRE, + JEDI +}; + +struct ReviewInput +{ + int stars {}; + std::optional commentary {}; +}; + +namespace object { + +class Character; + +class Human; +class Droid; +class Query; +class Review; +class Mutation; + +} // namespace object + +class Operations + : public service::Request +{ +public: + explicit Operations(std::shared_ptr query, std::shared_ptr mutation); + + template + explicit Operations(std::shared_ptr query, std::shared_ptr mutation) + : Operations { std::make_shared(std::move(query)), std::make_shared(std::move(mutation)) } + { + } + +private: + std::shared_ptr _query; + std::shared_ptr _mutation; +}; + +void AddCharacterDetails(const std::shared_ptr& typeCharacter, const std::shared_ptr& schema); + +void AddHumanDetails(const std::shared_ptr& typeHuman, const std::shared_ptr& schema); +void AddDroidDetails(const std::shared_ptr& typeDroid, const std::shared_ptr& schema); +void AddQueryDetails(const std::shared_ptr& typeQuery, const std::shared_ptr& schema); +void AddReviewDetails(const std::shared_ptr& typeReview, const std::shared_ptr& schema); +void AddMutationDetails(const std::shared_ptr& typeMutation, const std::shared_ptr& schema); + +std::shared_ptr GetSchema(); + +} // namespace learn +} // namespace graphql + +#endif // STARWARSSCHEMA_H diff --git a/samples/learn/learn_schema_files b/samples/learn/schema/learn_schema_files similarity index 83% rename from samples/learn/learn_schema_files rename to samples/learn/schema/learn_schema_files index 9bbec79d..4f897e53 100644 --- a/samples/learn/learn_schema_files +++ b/samples/learn/schema/learn_schema_files @@ -1,4 +1,5 @@ StarWarsSchema.cpp +CharacterObject.cpp HumanObject.cpp DroidObject.cpp QueryObject.cpp diff --git a/samples/schema.learn.graphql b/samples/learn/schema/schema.learn.graphql similarity index 100% rename from samples/schema.learn.graphql rename to samples/learn/schema/schema.learn.graphql diff --git a/samples/schema.validation.graphql b/samples/schema.validation.graphql deleted file mode 100644 index fe3b58ab..00000000 --- a/samples/schema.validation.graphql +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -"GraphQL validation [sample](http://spec.graphql.org/June2018/#example-26a9d)" -type Query { - dog: Dog -} - -enum DogCommand { SIT, DOWN, HEEL } - -type Dog implements Pet { - name: String! - nickname: String - barkVolume: Int - doesKnowCommand(dogCommand: DogCommand!): Boolean! - isHousetrained(atOtherHomes: Boolean): Boolean! - owner: Human -} - -interface Sentient { - name: String! -} - -interface Pet { - name: String! -} - -type Alien implements Sentient { - name: String! - homePlanet: String -} - -type Human implements Sentient { - name: String! -} - -enum CatCommand { JUMP } - -type Cat implements Pet { - name: String! - nickname: String - doesKnowCommand(catCommand: CatCommand!): Boolean! - meowVolume: Int -} - -union CatOrDog = Cat | Dog -union DogOrHuman = Dog | Human -union HumanOrAlien = Human | Alien - -"Support for [Counter Example 94](http://spec.graphql.org/June2018/#example-77c2e)" -type Mutation { - mutateDog: MutateDogResult -} - -"Support for [Counter Example 94](http://spec.graphql.org/June2018/#example-77c2e)" -type MutateDogResult { - id: ID! -} - -"Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b)" -type Subscription { - "Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b)" - newMessage: Message! - "Support for [Counter Example 99](http://spec.graphql.org/June2018/#example-3997d) - [Counter Example 100](http://spec.graphql.org/June2018/#example-18466)" - disallowedSecondRootField: Boolean! -} - -"Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b)" -type Message { - body: String - sender: ID! -} - -# http://spec.graphql.org/June2018/#example-9bada -extend type Query { - "Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e)" - human: Human - "Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e)" - pet: Pet - "Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e)" - catOrDog: CatOrDog -} - -"Support for [Example 120](http://spec.graphql.org/June2018/#example-1891c)" -type Arguments { - "Support for [Example 121](http://spec.graphql.org/June2018/#example-18fab)" - multipleReqs(x: Int!, y: Int!): Int! - booleanArgField(booleanArg: Boolean): Boolean - floatArgField(floatArg: Float): Float - intArgField(intArg: Int): Int - nonNullBooleanArgField(nonNullBooleanArg: Boolean!): Boolean! - nonNullBooleanListField(nonNullBooleanListArg: [Boolean!]): [Boolean!] - booleanListArgField(booleanListArg: [Boolean]!): [Boolean] - optionalNonNullBooleanArgField(optionalBooleanArg: Boolean! = false): Boolean! -} - -# http://spec.graphql.org/June2018/#example-1891c -extend type Query { - "Support for [Example 120](http://spec.graphql.org/June2018/#example-1891c)" - arguments: Arguments -} - -# http://spec.graphql.org/June2018/#example-6bbad -extend type Human { - "Support for [Counter Example 136](http://spec.graphql.org/June2018/#example-6bbad)" - pets: [Pet!]! -} - -"[Example 155](http://spec.graphql.org/June2018/#example-f3185)" -input ComplexInput { - name: String - owner: String -} - -extend type Query { - "[Example 155](http://spec.graphql.org/June2018/#example-f3185)" - findDog(complex: ComplexInput): Dog - "[Example 155](http://spec.graphql.org/June2018/#example-f3185)" - booleanList(booleanListArg: [Boolean!]): Boolean -} diff --git a/samples/separate/AppointmentConnectionObject.cpp b/samples/separate/AppointmentConnectionObject.cpp deleted file mode 100644 index 59001226..00000000 --- a/samples/separate/AppointmentConnectionObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -AppointmentConnection::AppointmentConnection() - : service::Object({ - "AppointmentConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> AppointmentConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentConnection::getPageInfo is not implemented)ex"); -} - -std::future AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> AppointmentConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentConnection::getEdges is not implemented)ex"); -} - -std::future AppointmentConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future AppointmentConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentConnection)gql" }, std::move(params)); -} - -} // namespace object - -void AddAppointmentConnectionDetails(std::shared_ptr typeAppointmentConnection, const std::shared_ptr& schema) -{ - typeAppointmentConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/AppointmentConnectionObject.h b/samples/separate/AppointmentConnectionObject.h deleted file mode 100644 index 76886da5..00000000 --- a/samples/separate/AppointmentConnectionObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef APPOINTMENTCONNECTIONOBJECT_H -#define APPOINTMENTCONNECTIONOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class AppointmentConnection - : public service::Object -{ -protected: - explicit AppointmentConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // APPOINTMENTCONNECTIONOBJECT_H diff --git a/samples/separate/AppointmentEdgeObject.cpp b/samples/separate/AppointmentEdgeObject.cpp deleted file mode 100644 index 3fc6c5af..00000000 --- a/samples/separate/AppointmentEdgeObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -AppointmentEdge::AppointmentEdge() - : service::Object({ - "AppointmentEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> AppointmentEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentEdge::getNode is not implemented)ex"); -} - -std::future AppointmentEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult AppointmentEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentEdge::getCursor is not implemented)ex"); -} - -std::future AppointmentEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future AppointmentEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentEdge)gql" }, std::move(params)); -} - -} // namespace object - -void AddAppointmentEdgeDetails(std::shared_ptr typeAppointmentEdge, const std::shared_ptr& schema) -{ - typeAppointmentEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Appointment")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/AppointmentEdgeObject.h b/samples/separate/AppointmentEdgeObject.h deleted file mode 100644 index 6b939423..00000000 --- a/samples/separate/AppointmentEdgeObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef APPOINTMENTEDGEOBJECT_H -#define APPOINTMENTEDGEOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class AppointmentEdge - : public service::Object -{ -protected: - explicit AppointmentEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // APPOINTMENTEDGEOBJECT_H diff --git a/samples/separate/AppointmentObject.cpp b/samples/separate/AppointmentObject.cpp deleted file mode 100644 index 9cc0282a..00000000 --- a/samples/separate/AppointmentObject.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -Appointment::Appointment() - : service::Object({ - "Node", - "UnionType", - "Appointment" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(when)gql"sv, [this](service::ResolverParams&& params) { return resolveWhen(std::move(params)); } }, - { R"gql(isNow)gql"sv, [this](service::ResolverParams&& params) { return resolveIsNow(std::move(params)); } }, - { R"gql(subject)gql"sv, [this](service::ResolverParams&& params) { return resolveSubject(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(forceError)gql"sv, [this](service::ResolverParams&& params) { return resolveForceError(std::move(params)); } } - }) -{ -} - -service::FieldResult Appointment::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); -} - -std::future Appointment::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getWhen(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getWhen is not implemented)ex"); -} - -std::future Appointment::resolveWhen(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getWhen(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getSubject(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getSubject is not implemented)ex"); -} - -std::future Appointment::resolveSubject(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getSubject(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Appointment::getIsNow(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getIsNow is not implemented)ex"); -} - -std::future Appointment::resolveIsNow(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getIsNow(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getForceError(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getForceError is not implemented)ex"); -} - -std::future Appointment::resolveForceError(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getForceError(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Appointment::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Appointment)gql" }, std::move(params)); -} - -} // namespace object - -void AddAppointmentDetails(std::shared_ptr typeAppointment, const std::shared_ptr& schema) -{ - typeAppointment->AddInterfaces({ - std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) - }); - typeAppointment->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(when)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("DateTime")), - schema::Field::Make(R"gql(subject)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(isNow)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - schema::Field::Make(R"gql(forceError)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/AppointmentObject.h b/samples/separate/AppointmentObject.h deleted file mode 100644 index 58c7763b..00000000 --- a/samples/separate/AppointmentObject.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef APPOINTMENTOBJECT_H -#define APPOINTMENTOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Appointment - : public service::Object - , public Node -{ -protected: - explicit Appointment(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getWhen(service::FieldParams&& params) const; - virtual service::FieldResult> getSubject(service::FieldParams&& params) const; - virtual service::FieldResult getIsNow(service::FieldParams&& params) const; - virtual service::FieldResult> getForceError(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveWhen(service::ResolverParams&& params); - std::future resolveSubject(service::ResolverParams&& params); - std::future resolveIsNow(service::ResolverParams&& params); - std::future resolveForceError(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // APPOINTMENTOBJECT_H diff --git a/samples/separate/CompleteTaskPayloadObject.cpp b/samples/separate/CompleteTaskPayloadObject.cpp deleted file mode 100644 index 130d0075..00000000 --- a/samples/separate/CompleteTaskPayloadObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -CompleteTaskPayload::CompleteTaskPayload() - : service::Object({ - "CompleteTaskPayload" - }, { - { R"gql(task)gql"sv, [this](service::ResolverParams&& params) { return resolveTask(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(clientMutationId)gql"sv, [this](service::ResolverParams&& params) { return resolveClientMutationId(std::move(params)); } } - }) -{ -} - -service::FieldResult> CompleteTaskPayload::getTask(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(CompleteTaskPayload::getTask is not implemented)ex"); -} - -std::future CompleteTaskPayload::resolveTask(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> CompleteTaskPayload::getClientMutationId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(CompleteTaskPayload::getClientMutationId is not implemented)ex"); -} - -std::future CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getClientMutationId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(CompleteTaskPayload)gql" }, std::move(params)); -} - -} // namespace object - -void AddCompleteTaskPayloadDetails(std::shared_ptr typeCompleteTaskPayload, const std::shared_ptr& schema) -{ - typeCompleteTaskPayload->AddFields({ - schema::Field::Make(R"gql(task)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), - schema::Field::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/CompleteTaskPayloadObject.h b/samples/separate/CompleteTaskPayloadObject.h deleted file mode 100644 index a88b53a3..00000000 --- a/samples/separate/CompleteTaskPayloadObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef COMPLETETASKPAYLOADOBJECT_H -#define COMPLETETASKPAYLOADOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class CompleteTaskPayload - : public service::Object -{ -protected: - explicit CompleteTaskPayload(); - -public: - virtual service::FieldResult> getTask(service::FieldParams&& params) const; - virtual service::FieldResult> getClientMutationId(service::FieldParams&& params) const; - -private: - std::future resolveTask(service::ResolverParams&& params); - std::future resolveClientMutationId(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // COMPLETETASKPAYLOADOBJECT_H diff --git a/samples/separate/ExpensiveObject.cpp b/samples/separate/ExpensiveObject.cpp deleted file mode 100644 index 7785d77f..00000000 --- a/samples/separate/ExpensiveObject.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -Expensive::Expensive() - : service::Object({ - "Expensive" - }, { - { R"gql(order)gql"sv, [this](service::ResolverParams&& params) { return resolveOrder(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult Expensive::getOrder(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Expensive::getOrder is not implemented)ex"); -} - -std::future Expensive::resolveOrder(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getOrder(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Expensive::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Expensive)gql" }, std::move(params)); -} - -} // namespace object - -void AddExpensiveDetails(std::shared_ptr typeExpensive, const std::shared_ptr& schema) -{ - typeExpensive->AddFields({ - schema::Field::Make(R"gql(order)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/ExpensiveObject.h b/samples/separate/ExpensiveObject.h deleted file mode 100644 index 791b4292..00000000 --- a/samples/separate/ExpensiveObject.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef EXPENSIVEOBJECT_H -#define EXPENSIVEOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Expensive - : public service::Object -{ -protected: - explicit Expensive(); - -public: - virtual service::FieldResult getOrder(service::FieldParams&& params) const; - -private: - std::future resolveOrder(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // EXPENSIVEOBJECT_H diff --git a/samples/separate/FolderConnectionObject.cpp b/samples/separate/FolderConnectionObject.cpp deleted file mode 100644 index 3380f997..00000000 --- a/samples/separate/FolderConnectionObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -FolderConnection::FolderConnection() - : service::Object({ - "FolderConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> FolderConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderConnection::getPageInfo is not implemented)ex"); -} - -std::future FolderConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> FolderConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderConnection::getEdges is not implemented)ex"); -} - -std::future FolderConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future FolderConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(FolderConnection)gql" }, std::move(params)); -} - -} // namespace object - -void AddFolderConnectionDetails(std::shared_ptr typeFolderConnection, const std::shared_ptr& schema) -{ - typeFolderConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/FolderConnectionObject.h b/samples/separate/FolderConnectionObject.h deleted file mode 100644 index aec397d4..00000000 --- a/samples/separate/FolderConnectionObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef FOLDERCONNECTIONOBJECT_H -#define FOLDERCONNECTIONOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class FolderConnection - : public service::Object -{ -protected: - explicit FolderConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // FOLDERCONNECTIONOBJECT_H diff --git a/samples/separate/FolderEdgeObject.cpp b/samples/separate/FolderEdgeObject.cpp deleted file mode 100644 index 7c641ce5..00000000 --- a/samples/separate/FolderEdgeObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -FolderEdge::FolderEdge() - : service::Object({ - "FolderEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> FolderEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderEdge::getNode is not implemented)ex"); -} - -std::future FolderEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult FolderEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderEdge::getCursor is not implemented)ex"); -} - -std::future FolderEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future FolderEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(FolderEdge)gql" }, std::move(params)); -} - -} // namespace object - -void AddFolderEdgeDetails(std::shared_ptr typeFolderEdge, const std::shared_ptr& schema) -{ - typeFolderEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Folder")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/FolderEdgeObject.h b/samples/separate/FolderEdgeObject.h deleted file mode 100644 index 00fbd677..00000000 --- a/samples/separate/FolderEdgeObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef FOLDEREDGEOBJECT_H -#define FOLDEREDGEOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class FolderEdge - : public service::Object -{ -protected: - explicit FolderEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // FOLDEREDGEOBJECT_H diff --git a/samples/separate/FolderObject.cpp b/samples/separate/FolderObject.cpp deleted file mode 100644 index d5c6b517..00000000 --- a/samples/separate/FolderObject.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -Folder::Folder() - : service::Object({ - "Node", - "UnionType", - "Folder" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(unreadCount)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCount(std::move(params)); } } - }) -{ -} - -service::FieldResult Folder::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getId is not implemented)ex"); -} - -std::future Folder::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Folder::getName(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getName is not implemented)ex"); -} - -std::future Folder::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Folder::getUnreadCount(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getUnreadCount is not implemented)ex"); -} - -std::future Folder::resolveUnreadCount(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCount(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Folder::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Folder)gql" }, std::move(params)); -} - -} // namespace object - -void AddFolderDetails(std::shared_ptr typeFolder, const std::shared_ptr& schema) -{ - typeFolder->AddInterfaces({ - std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) - }); - typeFolder->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(unreadCount)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/FolderObject.h b/samples/separate/FolderObject.h deleted file mode 100644 index e11053bf..00000000 --- a/samples/separate/FolderObject.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef FOLDEROBJECT_H -#define FOLDEROBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Folder - : public service::Object - , public Node -{ -protected: - explicit Folder(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getName(service::FieldParams&& params) const; - virtual service::FieldResult getUnreadCount(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveName(service::ResolverParams&& params); - std::future resolveUnreadCount(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // FOLDEROBJECT_H diff --git a/samples/separate/MutationObject.cpp b/samples/separate/MutationObject.cpp deleted file mode 100644 index c5f9d236..00000000 --- a/samples/separate/MutationObject.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -Mutation::Mutation() - : service::Object({ - "Mutation" - }, { - { R"gql(setFloat)gql"sv, [this](service::ResolverParams&& params) { return resolveSetFloat(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(completeTask)gql"sv, [this](service::ResolverParams&& params) { return resolveCompleteTask(std::move(params)); } } - }) -{ -} - -service::FieldResult> Mutation::applyCompleteTask(service::FieldParams&&, CompleteTaskInput&&) const -{ - throw std::runtime_error(R"ex(Mutation::applyCompleteTask is not implemented)ex"); -} - -std::future Mutation::resolveCompleteTask(service::ResolverParams&& params) -{ - auto argInput = service::ModifiedArgument::require("input", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = applyCompleteTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argInput)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Mutation::applySetFloat(service::FieldParams&&, response::FloatType&&) const -{ - throw std::runtime_error(R"ex(Mutation::applySetFloat is not implemented)ex"); -} - -std::future Mutation::resolveSetFloat(service::ResolverParams&& params) -{ - auto argValue = service::ModifiedArgument::require("value", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = applySetFloat(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argValue)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Mutation::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Mutation)gql" }, std::move(params)); -} - -} // namespace object - -void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema) -{ - typeMutation->AddFields({ - schema::Field::Make(R"gql(completeTask)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskPayload")), { - schema::InputValue::Make(R"gql(input)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskInput")), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(setFloat)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), { - schema::InputValue::Make(R"gql(value)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), R"gql()gql"sv) - }) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/MutationObject.h b/samples/separate/MutationObject.h deleted file mode 100644 index c5ab3977..00000000 --- a/samples/separate/MutationObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef MUTATIONOBJECT_H -#define MUTATIONOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Mutation - : public service::Object -{ -protected: - explicit Mutation(); - -public: - virtual service::FieldResult> applyCompleteTask(service::FieldParams&& params, CompleteTaskInput&& inputArg) const; - virtual service::FieldResult applySetFloat(service::FieldParams&& params, response::FloatType&& valueArg) const; - -private: - std::future resolveCompleteTask(service::ResolverParams&& params); - std::future resolveSetFloat(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // MUTATIONOBJECT_H diff --git a/samples/separate/NestedTypeObject.cpp b/samples/separate/NestedTypeObject.cpp deleted file mode 100644 index 285cfd11..00000000 --- a/samples/separate/NestedTypeObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -NestedType::NestedType() - : service::Object({ - "NestedType" - }, { - { R"gql(depth)gql"sv, [this](service::ResolverParams&& params) { return resolveDepth(std::move(params)); } }, - { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult NestedType::getDepth(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(NestedType::getDepth is not implemented)ex"); -} - -std::future NestedType::resolveDepth(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDepth(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> NestedType::getNested(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(NestedType::getNested is not implemented)ex"); -} - -std::future NestedType::resolveNested(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future NestedType::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(NestedType)gql" }, std::move(params)); -} - -} // namespace object - -void AddNestedTypeDetails(std::shared_ptr typeNestedType, const std::shared_ptr& schema) -{ - typeNestedType->AddFields({ - schema::Field::Make(R"gql(depth)gql"sv, R"md(Depth of the nested element)md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), - schema::Field::Make(R"gql(nested)gql"sv, R"md(Link to the next level)md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/NestedTypeObject.h b/samples/separate/NestedTypeObject.h deleted file mode 100644 index 94cb2418..00000000 --- a/samples/separate/NestedTypeObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef NESTEDTYPEOBJECT_H -#define NESTEDTYPEOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class NestedType - : public service::Object -{ -protected: - explicit NestedType(); - -public: - virtual service::FieldResult getDepth(service::FieldParams&& params) const; - virtual service::FieldResult> getNested(service::FieldParams&& params) const; - -private: - std::future resolveDepth(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // NESTEDTYPEOBJECT_H diff --git a/samples/separate/PageInfoObject.cpp b/samples/separate/PageInfoObject.cpp deleted file mode 100644 index 8c27b393..00000000 --- a/samples/separate/PageInfoObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -PageInfo::PageInfo() - : service::Object({ - "PageInfo" - }, { - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(hasNextPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasNextPage(std::move(params)); } }, - { R"gql(hasPreviousPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasPreviousPage(std::move(params)); } } - }) -{ -} - -service::FieldResult PageInfo::getHasNextPage(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(PageInfo::getHasNextPage is not implemented)ex"); -} - -std::future PageInfo::resolveHasNextPage(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHasNextPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult PageInfo::getHasPreviousPage(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(PageInfo::getHasPreviousPage is not implemented)ex"); -} - -std::future PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHasPreviousPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future PageInfo::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(PageInfo)gql" }, std::move(params)); -} - -} // namespace object - -void AddPageInfoDetails(std::shared_ptr typePageInfo, const std::shared_ptr& schema) -{ - typePageInfo->AddFields({ - schema::Field::Make(R"gql(hasNextPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - schema::Field::Make(R"gql(hasPreviousPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/PageInfoObject.h b/samples/separate/PageInfoObject.h deleted file mode 100644 index 337cbd4a..00000000 --- a/samples/separate/PageInfoObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef PAGEINFOOBJECT_H -#define PAGEINFOOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class PageInfo - : public service::Object -{ -protected: - explicit PageInfo(); - -public: - virtual service::FieldResult getHasNextPage(service::FieldParams&& params) const; - virtual service::FieldResult getHasPreviousPage(service::FieldParams&& params) const; - -private: - std::future resolveHasNextPage(service::ResolverParams&& params); - std::future resolveHasPreviousPage(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // PAGEINFOOBJECT_H diff --git a/samples/separate/QueryObject.h b/samples/separate/QueryObject.h deleted file mode 100644 index 55de9b70..00000000 --- a/samples/separate/QueryObject.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef QUERYOBJECT_H -#define QUERYOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Query - : public service::Object -{ -protected: - explicit Query(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params, response::IdType&& idArg) const; - virtual service::FieldResult> getAppointments(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult> getTasks(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult> getUnreadCounts(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult>> getAppointmentsById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult>> getTasksById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult>> getUnreadCountsById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult> getNested(service::FieldParams&& params) const; - virtual service::FieldResult getUnimplemented(service::FieldParams&& params) const; - virtual service::FieldResult>> getExpensive(service::FieldParams&& params) const; - virtual service::FieldResult getTestTaskState(service::FieldParams&& params) const; - virtual service::FieldResult>> getAnyType(service::FieldParams&& params, std::vector&& idsArg) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveAppointments(service::ResolverParams&& params); - std::future resolveTasks(service::ResolverParams&& params); - std::future resolveUnreadCounts(service::ResolverParams&& params); - std::future resolveAppointmentsById(service::ResolverParams&& params); - std::future resolveTasksById(service::ResolverParams&& params); - std::future resolveUnreadCountsById(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); - std::future resolveUnimplemented(service::ResolverParams&& params); - std::future resolveExpensive(service::ResolverParams&& params); - std::future resolveTestTaskState(service::ResolverParams&& params); - std::future resolveAnyType(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); - std::future resolve_schema(service::ResolverParams&& params); - std::future resolve_type(service::ResolverParams&& params); - - std::shared_ptr _schema; -}; - -} // namespace graphql::today::object - -#endif // QUERYOBJECT_H diff --git a/samples/separate/SubscriptionObject.cpp b/samples/separate/SubscriptionObject.cpp deleted file mode 100644 index 21b477be..00000000 --- a/samples/separate/SubscriptionObject.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -Subscription::Subscription() - : service::Object({ - "Subscription" - }, { - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(nodeChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNodeChange(std::move(params)); } }, - { R"gql(nextAppointmentChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNextAppointmentChange(std::move(params)); } } - }) -{ -} - -service::FieldResult> Subscription::getNextAppointmentChange(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Subscription::getNextAppointmentChange is not implemented)ex"); -} - -std::future Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNextAppointmentChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Subscription::getNodeChange(service::FieldParams&&, response::IdType&&) const -{ - throw std::runtime_error(R"ex(Subscription::getNodeChange is not implemented)ex"); -} - -std::future Subscription::resolveNodeChange(service::ResolverParams&& params) -{ - auto argId = service::ModifiedArgument::require("id", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNodeChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Subscription::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Subscription)gql" }, std::move(params)); -} - -} // namespace object - -void AddSubscriptionDetails(std::shared_ptr typeSubscription, const std::shared_ptr& schema) -{ - typeSubscription->AddFields({ - schema::Field::Make(R"gql(nextAppointmentChange)gql"sv, R"md()md"sv, std::make_optional(R"md(Need to deprecate a [field](http://spec.graphql.org/June2018/#sec-Deprecation))md"sv), schema->LookupType("Appointment")), - schema::Field::Make(R"gql(nodeChange)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Node")), { - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) - }) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/SubscriptionObject.h b/samples/separate/SubscriptionObject.h deleted file mode 100644 index b3aa3aa0..00000000 --- a/samples/separate/SubscriptionObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef SUBSCRIPTIONOBJECT_H -#define SUBSCRIPTIONOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Subscription - : public service::Object -{ -protected: - explicit Subscription(); - -public: - virtual service::FieldResult> getNextAppointmentChange(service::FieldParams&& params) const; - virtual service::FieldResult> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const; - -private: - std::future resolveNextAppointmentChange(service::ResolverParams&& params); - std::future resolveNodeChange(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // SUBSCRIPTIONOBJECT_H diff --git a/samples/separate/TaskConnectionObject.cpp b/samples/separate/TaskConnectionObject.cpp deleted file mode 100644 index e1eee585..00000000 --- a/samples/separate/TaskConnectionObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -TaskConnection::TaskConnection() - : service::Object({ - "TaskConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> TaskConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskConnection::getPageInfo is not implemented)ex"); -} - -std::future TaskConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> TaskConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskConnection::getEdges is not implemented)ex"); -} - -std::future TaskConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future TaskConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(TaskConnection)gql" }, std::move(params)); -} - -} // namespace object - -void AddTaskConnectionDetails(std::shared_ptr typeTaskConnection, const std::shared_ptr& schema) -{ - typeTaskConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/TaskConnectionObject.h b/samples/separate/TaskConnectionObject.h deleted file mode 100644 index d40a1e73..00000000 --- a/samples/separate/TaskConnectionObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TASKCONNECTIONOBJECT_H -#define TASKCONNECTIONOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class TaskConnection - : public service::Object -{ -protected: - explicit TaskConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // TASKCONNECTIONOBJECT_H diff --git a/samples/separate/TaskEdgeObject.cpp b/samples/separate/TaskEdgeObject.cpp deleted file mode 100644 index 631aaad4..00000000 --- a/samples/separate/TaskEdgeObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -TaskEdge::TaskEdge() - : service::Object({ - "TaskEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> TaskEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskEdge::getNode is not implemented)ex"); -} - -std::future TaskEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult TaskEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskEdge::getCursor is not implemented)ex"); -} - -std::future TaskEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future TaskEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(TaskEdge)gql" }, std::move(params)); -} - -} // namespace object - -void AddTaskEdgeDetails(std::shared_ptr typeTaskEdge, const std::shared_ptr& schema) -{ - typeTaskEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate/TaskEdgeObject.h b/samples/separate/TaskEdgeObject.h deleted file mode 100644 index f14b4227..00000000 --- a/samples/separate/TaskEdgeObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TASKEDGEOBJECT_H -#define TASKEDGEOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class TaskEdge - : public service::Object -{ -protected: - explicit TaskEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // TASKEDGEOBJECT_H diff --git a/samples/separate/TaskObject.h b/samples/separate/TaskObject.h deleted file mode 100644 index f98c21ac..00000000 --- a/samples/separate/TaskObject.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TASKOBJECT_H -#define TASKOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Task - : public service::Object - , public Node -{ -protected: - explicit Task(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getTitle(service::FieldParams&& params) const; - virtual service::FieldResult getIsComplete(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveTitle(service::ResolverParams&& params); - std::future resolveIsComplete(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // TASKOBJECT_H diff --git a/samples/separate/TodayObjects.h b/samples/separate/TodayObjects.h deleted file mode 100644 index 80502f8c..00000000 --- a/samples/separate/TodayObjects.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TODAYOBJECTS_H -#define TODAYOBJECTS_H - -#include "TodaySchema.h" - -#include "QueryObject.h" -#include "PageInfoObject.h" -#include "AppointmentEdgeObject.h" -#include "AppointmentConnectionObject.h" -#include "TaskEdgeObject.h" -#include "TaskConnectionObject.h" -#include "FolderEdgeObject.h" -#include "FolderConnectionObject.h" -#include "CompleteTaskPayloadObject.h" -#include "MutationObject.h" -#include "SubscriptionObject.h" -#include "AppointmentObject.h" -#include "TaskObject.h" -#include "FolderObject.h" -#include "NestedTypeObject.h" -#include "ExpensiveObject.h" - -#endif // TODAYOBJECTS_H diff --git a/samples/separate/TodaySchema.h b/samples/separate/TodaySchema.h deleted file mode 100644 index a85a43c7..00000000 --- a/samples/separate/TodaySchema.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TODAYSCHEMA_H -#define TODAYSCHEMA_H - -#include "graphqlservice/internal/Schema.h" - -// Check if the library version is compatible with schemagen 3.6.0 -static_assert(graphql::internal::MajorVersion == 3, "regenerate with schemagen: major version mismatch"); -static_assert(graphql::internal::MinorVersion == 6, "regenerate with schemagen: minor version mismatch"); - -#include -#include -#include - -namespace graphql { -namespace today { - -enum class TaskState -{ - New, - Started, - Complete, - Unassigned -}; - -struct CompleteTaskInput -{ - response::IdType id; - std::optional testTaskState; - std::optional isComplete; - std::optional clientMutationId; -}; - -struct ThirdNestedInput -{ - response::IdType id; -}; - -struct FourthNestedInput -{ - response::IdType id; -}; - -struct SecondNestedInput -{ - response::IdType id; - ThirdNestedInput third; -}; - -struct FirstNestedInput -{ - response::IdType id; - SecondNestedInput second; - ThirdNestedInput third; -}; - -namespace object { - -class Query; -class PageInfo; -class AppointmentEdge; -class AppointmentConnection; -class TaskEdge; -class TaskConnection; -class FolderEdge; -class FolderConnection; -class CompleteTaskPayload; -class Mutation; -class Subscription; -class Appointment; -class Task; -class Folder; -class NestedType; -class Expensive; - -} // namespace object - -struct Node -{ - virtual service::FieldResult getId(service::FieldParams&& params) const = 0; -}; - -class Operations - : public service::Request -{ -public: - explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription); - -private: - std::shared_ptr _query; - std::shared_ptr _mutation; - std::shared_ptr _subscription; -}; - -void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema); -void AddPageInfoDetails(std::shared_ptr typePageInfo, const std::shared_ptr& schema); -void AddAppointmentEdgeDetails(std::shared_ptr typeAppointmentEdge, const std::shared_ptr& schema); -void AddAppointmentConnectionDetails(std::shared_ptr typeAppointmentConnection, const std::shared_ptr& schema); -void AddTaskEdgeDetails(std::shared_ptr typeTaskEdge, const std::shared_ptr& schema); -void AddTaskConnectionDetails(std::shared_ptr typeTaskConnection, const std::shared_ptr& schema); -void AddFolderEdgeDetails(std::shared_ptr typeFolderEdge, const std::shared_ptr& schema); -void AddFolderConnectionDetails(std::shared_ptr typeFolderConnection, const std::shared_ptr& schema); -void AddCompleteTaskPayloadDetails(std::shared_ptr typeCompleteTaskPayload, const std::shared_ptr& schema); -void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema); -void AddSubscriptionDetails(std::shared_ptr typeSubscription, const std::shared_ptr& schema); -void AddAppointmentDetails(std::shared_ptr typeAppointment, const std::shared_ptr& schema); -void AddTaskDetails(std::shared_ptr typeTask, const std::shared_ptr& schema); -void AddFolderDetails(std::shared_ptr typeFolder, const std::shared_ptr& schema); -void AddNestedTypeDetails(std::shared_ptr typeNestedType, const std::shared_ptr& schema); -void AddExpensiveDetails(std::shared_ptr typeExpensive, const std::shared_ptr& schema); - -std::shared_ptr GetSchema(); - -} // namespace today -} // namespace graphql - -#endif // TODAYSCHEMA_H diff --git a/samples/separate_nointrospection/AppointmentConnectionObject.cpp b/samples/separate_nointrospection/AppointmentConnectionObject.cpp deleted file mode 100644 index 59001226..00000000 --- a/samples/separate_nointrospection/AppointmentConnectionObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -AppointmentConnection::AppointmentConnection() - : service::Object({ - "AppointmentConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> AppointmentConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentConnection::getPageInfo is not implemented)ex"); -} - -std::future AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> AppointmentConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentConnection::getEdges is not implemented)ex"); -} - -std::future AppointmentConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future AppointmentConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentConnection)gql" }, std::move(params)); -} - -} // namespace object - -void AddAppointmentConnectionDetails(std::shared_ptr typeAppointmentConnection, const std::shared_ptr& schema) -{ - typeAppointmentConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/AppointmentConnectionObject.h b/samples/separate_nointrospection/AppointmentConnectionObject.h deleted file mode 100644 index 76886da5..00000000 --- a/samples/separate_nointrospection/AppointmentConnectionObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef APPOINTMENTCONNECTIONOBJECT_H -#define APPOINTMENTCONNECTIONOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class AppointmentConnection - : public service::Object -{ -protected: - explicit AppointmentConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // APPOINTMENTCONNECTIONOBJECT_H diff --git a/samples/separate_nointrospection/AppointmentEdgeObject.cpp b/samples/separate_nointrospection/AppointmentEdgeObject.cpp deleted file mode 100644 index 3fc6c5af..00000000 --- a/samples/separate_nointrospection/AppointmentEdgeObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -AppointmentEdge::AppointmentEdge() - : service::Object({ - "AppointmentEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> AppointmentEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentEdge::getNode is not implemented)ex"); -} - -std::future AppointmentEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult AppointmentEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentEdge::getCursor is not implemented)ex"); -} - -std::future AppointmentEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future AppointmentEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentEdge)gql" }, std::move(params)); -} - -} // namespace object - -void AddAppointmentEdgeDetails(std::shared_ptr typeAppointmentEdge, const std::shared_ptr& schema) -{ - typeAppointmentEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Appointment")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/AppointmentEdgeObject.h b/samples/separate_nointrospection/AppointmentEdgeObject.h deleted file mode 100644 index 6b939423..00000000 --- a/samples/separate_nointrospection/AppointmentEdgeObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef APPOINTMENTEDGEOBJECT_H -#define APPOINTMENTEDGEOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class AppointmentEdge - : public service::Object -{ -protected: - explicit AppointmentEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // APPOINTMENTEDGEOBJECT_H diff --git a/samples/separate_nointrospection/AppointmentObject.cpp b/samples/separate_nointrospection/AppointmentObject.cpp deleted file mode 100644 index 9cc0282a..00000000 --- a/samples/separate_nointrospection/AppointmentObject.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -Appointment::Appointment() - : service::Object({ - "Node", - "UnionType", - "Appointment" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(when)gql"sv, [this](service::ResolverParams&& params) { return resolveWhen(std::move(params)); } }, - { R"gql(isNow)gql"sv, [this](service::ResolverParams&& params) { return resolveIsNow(std::move(params)); } }, - { R"gql(subject)gql"sv, [this](service::ResolverParams&& params) { return resolveSubject(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(forceError)gql"sv, [this](service::ResolverParams&& params) { return resolveForceError(std::move(params)); } } - }) -{ -} - -service::FieldResult Appointment::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); -} - -std::future Appointment::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getWhen(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getWhen is not implemented)ex"); -} - -std::future Appointment::resolveWhen(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getWhen(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getSubject(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getSubject is not implemented)ex"); -} - -std::future Appointment::resolveSubject(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getSubject(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Appointment::getIsNow(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getIsNow is not implemented)ex"); -} - -std::future Appointment::resolveIsNow(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getIsNow(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getForceError(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getForceError is not implemented)ex"); -} - -std::future Appointment::resolveForceError(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getForceError(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Appointment::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Appointment)gql" }, std::move(params)); -} - -} // namespace object - -void AddAppointmentDetails(std::shared_ptr typeAppointment, const std::shared_ptr& schema) -{ - typeAppointment->AddInterfaces({ - std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) - }); - typeAppointment->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(when)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("DateTime")), - schema::Field::Make(R"gql(subject)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(isNow)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - schema::Field::Make(R"gql(forceError)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/AppointmentObject.h b/samples/separate_nointrospection/AppointmentObject.h deleted file mode 100644 index 58c7763b..00000000 --- a/samples/separate_nointrospection/AppointmentObject.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef APPOINTMENTOBJECT_H -#define APPOINTMENTOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Appointment - : public service::Object - , public Node -{ -protected: - explicit Appointment(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getWhen(service::FieldParams&& params) const; - virtual service::FieldResult> getSubject(service::FieldParams&& params) const; - virtual service::FieldResult getIsNow(service::FieldParams&& params) const; - virtual service::FieldResult> getForceError(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveWhen(service::ResolverParams&& params); - std::future resolveSubject(service::ResolverParams&& params); - std::future resolveIsNow(service::ResolverParams&& params); - std::future resolveForceError(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // APPOINTMENTOBJECT_H diff --git a/samples/separate_nointrospection/CompleteTaskPayloadObject.cpp b/samples/separate_nointrospection/CompleteTaskPayloadObject.cpp deleted file mode 100644 index 130d0075..00000000 --- a/samples/separate_nointrospection/CompleteTaskPayloadObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -CompleteTaskPayload::CompleteTaskPayload() - : service::Object({ - "CompleteTaskPayload" - }, { - { R"gql(task)gql"sv, [this](service::ResolverParams&& params) { return resolveTask(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(clientMutationId)gql"sv, [this](service::ResolverParams&& params) { return resolveClientMutationId(std::move(params)); } } - }) -{ -} - -service::FieldResult> CompleteTaskPayload::getTask(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(CompleteTaskPayload::getTask is not implemented)ex"); -} - -std::future CompleteTaskPayload::resolveTask(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> CompleteTaskPayload::getClientMutationId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(CompleteTaskPayload::getClientMutationId is not implemented)ex"); -} - -std::future CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getClientMutationId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(CompleteTaskPayload)gql" }, std::move(params)); -} - -} // namespace object - -void AddCompleteTaskPayloadDetails(std::shared_ptr typeCompleteTaskPayload, const std::shared_ptr& schema) -{ - typeCompleteTaskPayload->AddFields({ - schema::Field::Make(R"gql(task)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), - schema::Field::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/CompleteTaskPayloadObject.h b/samples/separate_nointrospection/CompleteTaskPayloadObject.h deleted file mode 100644 index a88b53a3..00000000 --- a/samples/separate_nointrospection/CompleteTaskPayloadObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef COMPLETETASKPAYLOADOBJECT_H -#define COMPLETETASKPAYLOADOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class CompleteTaskPayload - : public service::Object -{ -protected: - explicit CompleteTaskPayload(); - -public: - virtual service::FieldResult> getTask(service::FieldParams&& params) const; - virtual service::FieldResult> getClientMutationId(service::FieldParams&& params) const; - -private: - std::future resolveTask(service::ResolverParams&& params); - std::future resolveClientMutationId(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // COMPLETETASKPAYLOADOBJECT_H diff --git a/samples/separate_nointrospection/ExpensiveObject.cpp b/samples/separate_nointrospection/ExpensiveObject.cpp deleted file mode 100644 index 7785d77f..00000000 --- a/samples/separate_nointrospection/ExpensiveObject.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -Expensive::Expensive() - : service::Object({ - "Expensive" - }, { - { R"gql(order)gql"sv, [this](service::ResolverParams&& params) { return resolveOrder(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult Expensive::getOrder(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Expensive::getOrder is not implemented)ex"); -} - -std::future Expensive::resolveOrder(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getOrder(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Expensive::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Expensive)gql" }, std::move(params)); -} - -} // namespace object - -void AddExpensiveDetails(std::shared_ptr typeExpensive, const std::shared_ptr& schema) -{ - typeExpensive->AddFields({ - schema::Field::Make(R"gql(order)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/ExpensiveObject.h b/samples/separate_nointrospection/ExpensiveObject.h deleted file mode 100644 index 791b4292..00000000 --- a/samples/separate_nointrospection/ExpensiveObject.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef EXPENSIVEOBJECT_H -#define EXPENSIVEOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Expensive - : public service::Object -{ -protected: - explicit Expensive(); - -public: - virtual service::FieldResult getOrder(service::FieldParams&& params) const; - -private: - std::future resolveOrder(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // EXPENSIVEOBJECT_H diff --git a/samples/separate_nointrospection/FolderConnectionObject.cpp b/samples/separate_nointrospection/FolderConnectionObject.cpp deleted file mode 100644 index 3380f997..00000000 --- a/samples/separate_nointrospection/FolderConnectionObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -FolderConnection::FolderConnection() - : service::Object({ - "FolderConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> FolderConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderConnection::getPageInfo is not implemented)ex"); -} - -std::future FolderConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> FolderConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderConnection::getEdges is not implemented)ex"); -} - -std::future FolderConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future FolderConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(FolderConnection)gql" }, std::move(params)); -} - -} // namespace object - -void AddFolderConnectionDetails(std::shared_ptr typeFolderConnection, const std::shared_ptr& schema) -{ - typeFolderConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/FolderConnectionObject.h b/samples/separate_nointrospection/FolderConnectionObject.h deleted file mode 100644 index aec397d4..00000000 --- a/samples/separate_nointrospection/FolderConnectionObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef FOLDERCONNECTIONOBJECT_H -#define FOLDERCONNECTIONOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class FolderConnection - : public service::Object -{ -protected: - explicit FolderConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // FOLDERCONNECTIONOBJECT_H diff --git a/samples/separate_nointrospection/FolderEdgeObject.cpp b/samples/separate_nointrospection/FolderEdgeObject.cpp deleted file mode 100644 index 7c641ce5..00000000 --- a/samples/separate_nointrospection/FolderEdgeObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -FolderEdge::FolderEdge() - : service::Object({ - "FolderEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> FolderEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderEdge::getNode is not implemented)ex"); -} - -std::future FolderEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult FolderEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderEdge::getCursor is not implemented)ex"); -} - -std::future FolderEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future FolderEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(FolderEdge)gql" }, std::move(params)); -} - -} // namespace object - -void AddFolderEdgeDetails(std::shared_ptr typeFolderEdge, const std::shared_ptr& schema) -{ - typeFolderEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Folder")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/FolderEdgeObject.h b/samples/separate_nointrospection/FolderEdgeObject.h deleted file mode 100644 index 00fbd677..00000000 --- a/samples/separate_nointrospection/FolderEdgeObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef FOLDEREDGEOBJECT_H -#define FOLDEREDGEOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class FolderEdge - : public service::Object -{ -protected: - explicit FolderEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // FOLDEREDGEOBJECT_H diff --git a/samples/separate_nointrospection/FolderObject.cpp b/samples/separate_nointrospection/FolderObject.cpp deleted file mode 100644 index d5c6b517..00000000 --- a/samples/separate_nointrospection/FolderObject.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -Folder::Folder() - : service::Object({ - "Node", - "UnionType", - "Folder" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(unreadCount)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCount(std::move(params)); } } - }) -{ -} - -service::FieldResult Folder::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getId is not implemented)ex"); -} - -std::future Folder::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Folder::getName(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getName is not implemented)ex"); -} - -std::future Folder::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Folder::getUnreadCount(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getUnreadCount is not implemented)ex"); -} - -std::future Folder::resolveUnreadCount(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCount(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Folder::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Folder)gql" }, std::move(params)); -} - -} // namespace object - -void AddFolderDetails(std::shared_ptr typeFolder, const std::shared_ptr& schema) -{ - typeFolder->AddInterfaces({ - std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) - }); - typeFolder->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(unreadCount)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/FolderObject.h b/samples/separate_nointrospection/FolderObject.h deleted file mode 100644 index e11053bf..00000000 --- a/samples/separate_nointrospection/FolderObject.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef FOLDEROBJECT_H -#define FOLDEROBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Folder - : public service::Object - , public Node -{ -protected: - explicit Folder(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getName(service::FieldParams&& params) const; - virtual service::FieldResult getUnreadCount(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveName(service::ResolverParams&& params); - std::future resolveUnreadCount(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // FOLDEROBJECT_H diff --git a/samples/separate_nointrospection/MutationObject.cpp b/samples/separate_nointrospection/MutationObject.cpp deleted file mode 100644 index c5f9d236..00000000 --- a/samples/separate_nointrospection/MutationObject.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -Mutation::Mutation() - : service::Object({ - "Mutation" - }, { - { R"gql(setFloat)gql"sv, [this](service::ResolverParams&& params) { return resolveSetFloat(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(completeTask)gql"sv, [this](service::ResolverParams&& params) { return resolveCompleteTask(std::move(params)); } } - }) -{ -} - -service::FieldResult> Mutation::applyCompleteTask(service::FieldParams&&, CompleteTaskInput&&) const -{ - throw std::runtime_error(R"ex(Mutation::applyCompleteTask is not implemented)ex"); -} - -std::future Mutation::resolveCompleteTask(service::ResolverParams&& params) -{ - auto argInput = service::ModifiedArgument::require("input", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = applyCompleteTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argInput)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Mutation::applySetFloat(service::FieldParams&&, response::FloatType&&) const -{ - throw std::runtime_error(R"ex(Mutation::applySetFloat is not implemented)ex"); -} - -std::future Mutation::resolveSetFloat(service::ResolverParams&& params) -{ - auto argValue = service::ModifiedArgument::require("value", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = applySetFloat(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argValue)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Mutation::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Mutation)gql" }, std::move(params)); -} - -} // namespace object - -void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema) -{ - typeMutation->AddFields({ - schema::Field::Make(R"gql(completeTask)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskPayload")), { - schema::InputValue::Make(R"gql(input)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskInput")), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(setFloat)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), { - schema::InputValue::Make(R"gql(value)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), R"gql()gql"sv) - }) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/MutationObject.h b/samples/separate_nointrospection/MutationObject.h deleted file mode 100644 index c5ab3977..00000000 --- a/samples/separate_nointrospection/MutationObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef MUTATIONOBJECT_H -#define MUTATIONOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Mutation - : public service::Object -{ -protected: - explicit Mutation(); - -public: - virtual service::FieldResult> applyCompleteTask(service::FieldParams&& params, CompleteTaskInput&& inputArg) const; - virtual service::FieldResult applySetFloat(service::FieldParams&& params, response::FloatType&& valueArg) const; - -private: - std::future resolveCompleteTask(service::ResolverParams&& params); - std::future resolveSetFloat(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // MUTATIONOBJECT_H diff --git a/samples/separate_nointrospection/NestedTypeObject.cpp b/samples/separate_nointrospection/NestedTypeObject.cpp deleted file mode 100644 index ffb3d909..00000000 --- a/samples/separate_nointrospection/NestedTypeObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -NestedType::NestedType() - : service::Object({ - "NestedType" - }, { - { R"gql(depth)gql"sv, [this](service::ResolverParams&& params) { return resolveDepth(std::move(params)); } }, - { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult NestedType::getDepth(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(NestedType::getDepth is not implemented)ex"); -} - -std::future NestedType::resolveDepth(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDepth(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> NestedType::getNested(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(NestedType::getNested is not implemented)ex"); -} - -std::future NestedType::resolveNested(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future NestedType::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(NestedType)gql" }, std::move(params)); -} - -} // namespace object - -void AddNestedTypeDetails(std::shared_ptr typeNestedType, const std::shared_ptr& schema) -{ - typeNestedType->AddFields({ - schema::Field::Make(R"gql(depth)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), - schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/NestedTypeObject.h b/samples/separate_nointrospection/NestedTypeObject.h deleted file mode 100644 index 94cb2418..00000000 --- a/samples/separate_nointrospection/NestedTypeObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef NESTEDTYPEOBJECT_H -#define NESTEDTYPEOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class NestedType - : public service::Object -{ -protected: - explicit NestedType(); - -public: - virtual service::FieldResult getDepth(service::FieldParams&& params) const; - virtual service::FieldResult> getNested(service::FieldParams&& params) const; - -private: - std::future resolveDepth(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // NESTEDTYPEOBJECT_H diff --git a/samples/separate_nointrospection/PageInfoObject.cpp b/samples/separate_nointrospection/PageInfoObject.cpp deleted file mode 100644 index 8c27b393..00000000 --- a/samples/separate_nointrospection/PageInfoObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -PageInfo::PageInfo() - : service::Object({ - "PageInfo" - }, { - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(hasNextPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasNextPage(std::move(params)); } }, - { R"gql(hasPreviousPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasPreviousPage(std::move(params)); } } - }) -{ -} - -service::FieldResult PageInfo::getHasNextPage(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(PageInfo::getHasNextPage is not implemented)ex"); -} - -std::future PageInfo::resolveHasNextPage(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHasNextPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult PageInfo::getHasPreviousPage(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(PageInfo::getHasPreviousPage is not implemented)ex"); -} - -std::future PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHasPreviousPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future PageInfo::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(PageInfo)gql" }, std::move(params)); -} - -} // namespace object - -void AddPageInfoDetails(std::shared_ptr typePageInfo, const std::shared_ptr& schema) -{ - typePageInfo->AddFields({ - schema::Field::Make(R"gql(hasNextPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - schema::Field::Make(R"gql(hasPreviousPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/PageInfoObject.h b/samples/separate_nointrospection/PageInfoObject.h deleted file mode 100644 index 337cbd4a..00000000 --- a/samples/separate_nointrospection/PageInfoObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef PAGEINFOOBJECT_H -#define PAGEINFOOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class PageInfo - : public service::Object -{ -protected: - explicit PageInfo(); - -public: - virtual service::FieldResult getHasNextPage(service::FieldParams&& params) const; - virtual service::FieldResult getHasPreviousPage(service::FieldParams&& params) const; - -private: - std::future resolveHasNextPage(service::ResolverParams&& params); - std::future resolveHasPreviousPage(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // PAGEINFOOBJECT_H diff --git a/samples/separate_nointrospection/QueryObject.h b/samples/separate_nointrospection/QueryObject.h deleted file mode 100644 index 91da5182..00000000 --- a/samples/separate_nointrospection/QueryObject.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef QUERYOBJECT_H -#define QUERYOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Query - : public service::Object -{ -protected: - explicit Query(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params, response::IdType&& idArg) const; - virtual service::FieldResult> getAppointments(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult> getTasks(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult> getUnreadCounts(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult>> getAppointmentsById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult>> getTasksById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult>> getUnreadCountsById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult> getNested(service::FieldParams&& params) const; - virtual service::FieldResult getUnimplemented(service::FieldParams&& params) const; - virtual service::FieldResult>> getExpensive(service::FieldParams&& params) const; - virtual service::FieldResult getTestTaskState(service::FieldParams&& params) const; - virtual service::FieldResult>> getAnyType(service::FieldParams&& params, std::vector&& idsArg) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveAppointments(service::ResolverParams&& params); - std::future resolveTasks(service::ResolverParams&& params); - std::future resolveUnreadCounts(service::ResolverParams&& params); - std::future resolveAppointmentsById(service::ResolverParams&& params); - std::future resolveTasksById(service::ResolverParams&& params); - std::future resolveUnreadCountsById(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); - std::future resolveUnimplemented(service::ResolverParams&& params); - std::future resolveExpensive(service::ResolverParams&& params); - std::future resolveTestTaskState(service::ResolverParams&& params); - std::future resolveAnyType(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // QUERYOBJECT_H diff --git a/samples/separate_nointrospection/SubscriptionObject.cpp b/samples/separate_nointrospection/SubscriptionObject.cpp deleted file mode 100644 index 21b477be..00000000 --- a/samples/separate_nointrospection/SubscriptionObject.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -Subscription::Subscription() - : service::Object({ - "Subscription" - }, { - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(nodeChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNodeChange(std::move(params)); } }, - { R"gql(nextAppointmentChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNextAppointmentChange(std::move(params)); } } - }) -{ -} - -service::FieldResult> Subscription::getNextAppointmentChange(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Subscription::getNextAppointmentChange is not implemented)ex"); -} - -std::future Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNextAppointmentChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Subscription::getNodeChange(service::FieldParams&&, response::IdType&&) const -{ - throw std::runtime_error(R"ex(Subscription::getNodeChange is not implemented)ex"); -} - -std::future Subscription::resolveNodeChange(service::ResolverParams&& params) -{ - auto argId = service::ModifiedArgument::require("id", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNodeChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Subscription::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Subscription)gql" }, std::move(params)); -} - -} // namespace object - -void AddSubscriptionDetails(std::shared_ptr typeSubscription, const std::shared_ptr& schema) -{ - typeSubscription->AddFields({ - schema::Field::Make(R"gql(nextAppointmentChange)gql"sv, R"md()md"sv, std::make_optional(R"md(Need to deprecate a [field](http://spec.graphql.org/June2018/#sec-Deprecation))md"sv), schema->LookupType("Appointment")), - schema::Field::Make(R"gql(nodeChange)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Node")), { - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) - }) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/SubscriptionObject.h b/samples/separate_nointrospection/SubscriptionObject.h deleted file mode 100644 index b3aa3aa0..00000000 --- a/samples/separate_nointrospection/SubscriptionObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef SUBSCRIPTIONOBJECT_H -#define SUBSCRIPTIONOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Subscription - : public service::Object -{ -protected: - explicit Subscription(); - -public: - virtual service::FieldResult> getNextAppointmentChange(service::FieldParams&& params) const; - virtual service::FieldResult> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const; - -private: - std::future resolveNextAppointmentChange(service::ResolverParams&& params); - std::future resolveNodeChange(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // SUBSCRIPTIONOBJECT_H diff --git a/samples/separate_nointrospection/TaskConnectionObject.cpp b/samples/separate_nointrospection/TaskConnectionObject.cpp deleted file mode 100644 index e1eee585..00000000 --- a/samples/separate_nointrospection/TaskConnectionObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -TaskConnection::TaskConnection() - : service::Object({ - "TaskConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> TaskConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskConnection::getPageInfo is not implemented)ex"); -} - -std::future TaskConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> TaskConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskConnection::getEdges is not implemented)ex"); -} - -std::future TaskConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future TaskConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(TaskConnection)gql" }, std::move(params)); -} - -} // namespace object - -void AddTaskConnectionDetails(std::shared_ptr typeTaskConnection, const std::shared_ptr& schema) -{ - typeTaskConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/TaskConnectionObject.h b/samples/separate_nointrospection/TaskConnectionObject.h deleted file mode 100644 index d40a1e73..00000000 --- a/samples/separate_nointrospection/TaskConnectionObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TASKCONNECTIONOBJECT_H -#define TASKCONNECTIONOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class TaskConnection - : public service::Object -{ -protected: - explicit TaskConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // TASKCONNECTIONOBJECT_H diff --git a/samples/separate_nointrospection/TaskEdgeObject.cpp b/samples/separate_nointrospection/TaskEdgeObject.cpp deleted file mode 100644 index 631aaad4..00000000 --- a/samples/separate_nointrospection/TaskEdgeObject.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql::today { -namespace object { - -TaskEdge::TaskEdge() - : service::Object({ - "TaskEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> TaskEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskEdge::getNode is not implemented)ex"); -} - -std::future TaskEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult TaskEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskEdge::getCursor is not implemented)ex"); -} - -std::future TaskEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future TaskEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(TaskEdge)gql" }, std::move(params)); -} - -} // namespace object - -void AddTaskEdgeDetails(std::shared_ptr typeTaskEdge, const std::shared_ptr& schema) -{ - typeTaskEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); -} - -} // namespace graphql::today diff --git a/samples/separate_nointrospection/TaskEdgeObject.h b/samples/separate_nointrospection/TaskEdgeObject.h deleted file mode 100644 index f14b4227..00000000 --- a/samples/separate_nointrospection/TaskEdgeObject.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TASKEDGEOBJECT_H -#define TASKEDGEOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class TaskEdge - : public service::Object -{ -protected: - explicit TaskEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // TASKEDGEOBJECT_H diff --git a/samples/separate_nointrospection/TaskObject.h b/samples/separate_nointrospection/TaskObject.h deleted file mode 100644 index f98c21ac..00000000 --- a/samples/separate_nointrospection/TaskObject.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TASKOBJECT_H -#define TASKOBJECT_H - -#include "TodaySchema.h" - -namespace graphql::today::object { - -class Task - : public service::Object - , public Node -{ -protected: - explicit Task(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getTitle(service::FieldParams&& params) const; - virtual service::FieldResult getIsComplete(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveTitle(service::ResolverParams&& params); - std::future resolveIsComplete(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace graphql::today::object - -#endif // TASKOBJECT_H diff --git a/samples/separate_nointrospection/TodayObjects.h b/samples/separate_nointrospection/TodayObjects.h deleted file mode 100644 index 80502f8c..00000000 --- a/samples/separate_nointrospection/TodayObjects.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TODAYOBJECTS_H -#define TODAYOBJECTS_H - -#include "TodaySchema.h" - -#include "QueryObject.h" -#include "PageInfoObject.h" -#include "AppointmentEdgeObject.h" -#include "AppointmentConnectionObject.h" -#include "TaskEdgeObject.h" -#include "TaskConnectionObject.h" -#include "FolderEdgeObject.h" -#include "FolderConnectionObject.h" -#include "CompleteTaskPayloadObject.h" -#include "MutationObject.h" -#include "SubscriptionObject.h" -#include "AppointmentObject.h" -#include "TaskObject.h" -#include "FolderObject.h" -#include "NestedTypeObject.h" -#include "ExpensiveObject.h" - -#endif // TODAYOBJECTS_H diff --git a/samples/separate_nointrospection/TodaySchema.h b/samples/separate_nointrospection/TodaySchema.h deleted file mode 100644 index a85a43c7..00000000 --- a/samples/separate_nointrospection/TodaySchema.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TODAYSCHEMA_H -#define TODAYSCHEMA_H - -#include "graphqlservice/internal/Schema.h" - -// Check if the library version is compatible with schemagen 3.6.0 -static_assert(graphql::internal::MajorVersion == 3, "regenerate with schemagen: major version mismatch"); -static_assert(graphql::internal::MinorVersion == 6, "regenerate with schemagen: minor version mismatch"); - -#include -#include -#include - -namespace graphql { -namespace today { - -enum class TaskState -{ - New, - Started, - Complete, - Unassigned -}; - -struct CompleteTaskInput -{ - response::IdType id; - std::optional testTaskState; - std::optional isComplete; - std::optional clientMutationId; -}; - -struct ThirdNestedInput -{ - response::IdType id; -}; - -struct FourthNestedInput -{ - response::IdType id; -}; - -struct SecondNestedInput -{ - response::IdType id; - ThirdNestedInput third; -}; - -struct FirstNestedInput -{ - response::IdType id; - SecondNestedInput second; - ThirdNestedInput third; -}; - -namespace object { - -class Query; -class PageInfo; -class AppointmentEdge; -class AppointmentConnection; -class TaskEdge; -class TaskConnection; -class FolderEdge; -class FolderConnection; -class CompleteTaskPayload; -class Mutation; -class Subscription; -class Appointment; -class Task; -class Folder; -class NestedType; -class Expensive; - -} // namespace object - -struct Node -{ - virtual service::FieldResult getId(service::FieldParams&& params) const = 0; -}; - -class Operations - : public service::Request -{ -public: - explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription); - -private: - std::shared_ptr _query; - std::shared_ptr _mutation; - std::shared_ptr _subscription; -}; - -void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema); -void AddPageInfoDetails(std::shared_ptr typePageInfo, const std::shared_ptr& schema); -void AddAppointmentEdgeDetails(std::shared_ptr typeAppointmentEdge, const std::shared_ptr& schema); -void AddAppointmentConnectionDetails(std::shared_ptr typeAppointmentConnection, const std::shared_ptr& schema); -void AddTaskEdgeDetails(std::shared_ptr typeTaskEdge, const std::shared_ptr& schema); -void AddTaskConnectionDetails(std::shared_ptr typeTaskConnection, const std::shared_ptr& schema); -void AddFolderEdgeDetails(std::shared_ptr typeFolderEdge, const std::shared_ptr& schema); -void AddFolderConnectionDetails(std::shared_ptr typeFolderConnection, const std::shared_ptr& schema); -void AddCompleteTaskPayloadDetails(std::shared_ptr typeCompleteTaskPayload, const std::shared_ptr& schema); -void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema); -void AddSubscriptionDetails(std::shared_ptr typeSubscription, const std::shared_ptr& schema); -void AddAppointmentDetails(std::shared_ptr typeAppointment, const std::shared_ptr& schema); -void AddTaskDetails(std::shared_ptr typeTask, const std::shared_ptr& schema); -void AddFolderDetails(std::shared_ptr typeFolder, const std::shared_ptr& schema); -void AddNestedTypeDetails(std::shared_ptr typeNestedType, const std::shared_ptr& schema); -void AddExpensiveDetails(std::shared_ptr typeExpensive, const std::shared_ptr& schema); - -std::shared_ptr GetSchema(); - -} // namespace today -} // namespace graphql - -#endif // TODAYSCHEMA_H diff --git a/samples/star_wars/DroidData.cpp b/samples/star_wars/DroidData.cpp deleted file mode 100644 index b3ae6007..00000000 --- a/samples/star_wars/DroidData.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "DroidData.h" - -#include "HumanData.h" - -namespace graphql::learn { - -Droid::Droid(response::StringType id, std::optional name, - std::vector appearsIn, std::optional primaryFunction) noexcept - : id_ { std::move(id) } - , name_ { std::move(name) } - , appearsIn_ { std::move(appearsIn) } - , primaryFunction_ { std::move(primaryFunction) } -{ -} - -const response::StringType& Droid::id() const noexcept -{ - return id_; -} - -void Droid::addFriends( - std::vector, std::shared_ptr>> friends) noexcept -{ - friends_.resize(friends.size()); - - std::transform(friends.begin(), - friends.end(), - friends_.begin(), - [](const auto& spFriend) noexcept { - return std::visit( - [](const auto& hero) noexcept { - return WeakHero { - std::weak_ptr::element_type> { hero } - }; - }, - spFriend); - }); -} - -service::FieldResult Droid::getId(service::FieldParams&& params) const -{ - return { id_ }; -} - -service::FieldResult> Droid::getName( - service::FieldParams&& params) const -{ - return { name_ }; -} - -service::FieldResult>>> Droid:: - getFriends(service::FieldParams&& params) const -{ - std::vector> result(friends_.size()); - - std::transform(friends_.begin(), - friends_.end(), - std::back_inserter(result), - [](const auto& wpFriend) noexcept { - return std::visit( - [](const auto& hero) noexcept { - return std::static_pointer_cast(hero.lock()); - }, - wpFriend); - }); - result.erase(std::remove_if(result.begin(), - result.end(), - [](const auto& entry) noexcept { - return !entry; - }), - result.end()); - - return { result.empty() ? std::nullopt : std::make_optional(std::move(result)) }; -} - -service::FieldResult>>> Droid::getAppearsIn( - service::FieldParams&& params) const -{ - std::vector> result(appearsIn_.size()); - - std::transform(appearsIn_.begin(), - appearsIn_.end(), - result.begin(), - [](const auto& entry) noexcept { - return std::make_optional(entry); - }); - - return { result.empty() ? std::nullopt : std::make_optional(std::move(result)) }; -} - -service::FieldResult> Droid::getPrimaryFunction( - service::FieldParams&& params) const -{ - return { primaryFunction_ }; -} - -} // namespace graphql::learn diff --git a/samples/star_wars/DroidData.h b/samples/star_wars/DroidData.h deleted file mode 100644 index 90b9c781..00000000 --- a/samples/star_wars/DroidData.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#ifndef DROIDDATA_H -#define DROIDDATA_H - -#include "HeroData.h" - -#include "DroidObject.h" - -namespace graphql::learn { - -class Human; - -class Droid : public object::Droid -{ -public: - explicit Droid(response::StringType id, std::optional name, - std::vector appearsIn, - std::optional primaryFunction) noexcept; - - const response::StringType& id() const noexcept; - void addFriends(std::vector friends) noexcept; - - service::FieldResult getId(service::FieldParams&& params) const final; - service::FieldResult> getName( - service::FieldParams&& params) const final; - service::FieldResult>>> getFriends( - service::FieldParams&& params) const final; - service::FieldResult>>> getAppearsIn( - service::FieldParams&& params) const final; - service::FieldResult> getPrimaryFunction( - service::FieldParams&& params) const final; - -private: - const response::StringType id_; - const std::optional name_; - const std::vector appearsIn_; - const std::optional primaryFunction_; - - std::vector friends_; -}; - -} // namespace graphql::learn - -#endif // DROIDDATA_H diff --git a/samples/star_wars/HumanData.cpp b/samples/star_wars/HumanData.cpp deleted file mode 100644 index 8c6801f2..00000000 --- a/samples/star_wars/HumanData.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "HumanData.h" - -#include "DroidData.h" - -namespace graphql::learn { - -Human::Human(response::StringType id, std::optional name, - std::vector appearsIn, std::optional homePlanet) noexcept - : id_ { std::move(id) } - , name_ { std::move(name) } - , appearsIn_ { std::move(appearsIn) } - , homePlanet_ { std::move(homePlanet) } -{ -} - -const response::StringType& Human::id() const noexcept -{ - return id_; -} - -void Human::addFriends(std::vector friends) noexcept -{ - friends_.resize(friends.size()); - - std::transform(friends.begin(), - friends.end(), - friends_.begin(), - [](const auto& spFriend) noexcept { - return std::visit( - [](const auto& hero) noexcept { - return WeakHero { - std::weak_ptr::element_type> { hero } - }; - }, - spFriend); - }); -} - -service::FieldResult Human::getId(service::FieldParams&& params) const -{ - return { id_ }; -} - -service::FieldResult> Human::getName( - service::FieldParams&& params) const -{ - return { name_ }; -} - -service::FieldResult>>> Human:: - getFriends(service::FieldParams&& params) const -{ - std::vector> result(friends_.size()); - - std::transform(friends_.begin(), - friends_.end(), - std::back_inserter(result), - [](const auto& wpFriend) noexcept { - return std::visit( - [](const auto& hero) noexcept { - return std::static_pointer_cast(hero.lock()); - }, - wpFriend); - }); - result.erase(std::remove_if(result.begin(), - result.end(), - [](const auto& entry) noexcept { - return !entry; - }), - result.end()); - - return { result.empty() ? std::nullopt : std::make_optional(std::move(result)) }; -} - -service::FieldResult>>> Human::getAppearsIn( - service::FieldParams&& params) const -{ - std::vector> result(appearsIn_.size()); - - std::transform(appearsIn_.begin(), - appearsIn_.end(), - result.begin(), - [](const auto& entry) noexcept { - return std::make_optional(entry); - }); - - return { result.empty() ? std::nullopt : std::make_optional(std::move(result)) }; -} - -service::FieldResult> Human::getHomePlanet( - service::FieldParams&& params) const -{ - return { homePlanet_ }; -} - -} // namespace graphql::learn diff --git a/samples/star_wars/HumanData.h b/samples/star_wars/HumanData.h deleted file mode 100644 index 280acc94..00000000 --- a/samples/star_wars/HumanData.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#ifndef HUMANDATA_H -#define HUMANDATA_H - -#include "HeroData.h" - -#include "HumanObject.h" - -namespace graphql::learn { - -class Human : public object::Human -{ -public: - explicit Human(response::StringType id, std::optional name, - std::vector appearsIn, - std::optional homePlanet) noexcept; - - const response::StringType& id() const noexcept; - void addFriends(std::vector friends) noexcept; - - service::FieldResult getId(service::FieldParams&& params) const final; - service::FieldResult> getName( - service::FieldParams&& params) const final; - service::FieldResult>>> getFriends( - service::FieldParams&& params) const final; - service::FieldResult>>> getAppearsIn( - service::FieldParams&& params) const final; - service::FieldResult> getHomePlanet( - service::FieldParams&& params) const final; - -private: - const response::StringType id_; - const std::optional name_; - const std::vector appearsIn_; - const std::optional homePlanet_; - - std::vector friends_; -}; - -} // namespace graphql::learn - -#endif // HUMANDATA_H diff --git a/samples/star_wars/QueryData.cpp b/samples/star_wars/QueryData.cpp deleted file mode 100644 index 31a9ec01..00000000 --- a/samples/star_wars/QueryData.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "QueryData.h" - -namespace graphql::learn { - -Query::Query(std::map heroes, - std::map> humans, - std::map> droids) noexcept - : heroes_ { std::move(heroes) } - , humans_ { std::move(humans) } - , droids_ { std::move(droids) } -{ -} - -service::FieldResult> Query::getHero( - service::FieldParams&&, std::optional&& episodeArg) const -{ - std::shared_ptr result; - const auto episode = episodeArg ? *episodeArg : Episode::NEW_HOPE; - - if (const auto itr = heroes_.find(episode); itr != heroes_.end()) - { - result = std::visit( - [](const auto& hero) noexcept { - return std::static_pointer_cast(hero); - }, - itr->second); - } - - return { result }; -} - -service::FieldResult> Query::getHuman( - service::FieldParams&&, response::StringType&& idArg) const -{ - std::shared_ptr result; - - if (const auto itr = humans_.find(idArg); itr != humans_.end()) - { - result = itr->second; - } - - return { result }; -} - -service::FieldResult> Query::getDroid( - service::FieldParams&&, response::StringType&& idArg) const -{ - std::shared_ptr result; - - if (const auto itr = droids_.find(idArg); itr != droids_.end()) - { - result = itr->second; - } - - return { result }; -} - -} // namespace graphql::learn diff --git a/samples/star_wars/QueryData.h b/samples/star_wars/QueryData.h deleted file mode 100644 index 3dbdc109..00000000 --- a/samples/star_wars/QueryData.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#ifndef QUERYDATA_H -#define QUERYDATA_H - -#include "QueryObject.h" - -#include "DroidData.h" -#include "HumanData.h" - -namespace graphql::learn { - -class Query : public object::Query -{ -public: - explicit Query(std::map heroes, - std::map> humans, - std::map> droids) noexcept; - - service::FieldResult> getHero( - service::FieldParams&& params, std::optional&& episodeArg) const final; - service::FieldResult> getHuman( - service::FieldParams&& params, response::StringType&& idArg) const final; - service::FieldResult> getDroid( - service::FieldParams&& params, response::StringType&& idArg) const final; - -private: - const std::map heroes_; - const std::map> humans_; - const std::map> droids_; -}; - -} // namespace graphql::learn - -#endif // QUERYDATA_H diff --git a/samples/star_wars/ReviewData.cpp b/samples/star_wars/ReviewData.cpp deleted file mode 100644 index 0c066be3..00000000 --- a/samples/star_wars/ReviewData.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "ReviewData.h" - -namespace graphql::learn { - -Review::Review(response::IntType stars, std::optional commentary) noexcept - : stars_ { stars } - , commentary_ { std::move(commentary) } -{ -} - -service::FieldResult Review::getStars(service::FieldParams&& params) const -{ - return { stars_ }; -} - -service::FieldResult> Review::getCommentary( - service::FieldParams&& params) const -{ - return { commentary_ }; -} - -} // namespace graphql::learn diff --git a/samples/star_wars/ReviewData.h b/samples/star_wars/ReviewData.h deleted file mode 100644 index 36661860..00000000 --- a/samples/star_wars/ReviewData.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#ifndef REVIEWDATA_H -#define REVIEWDATA_H - -#include "ReviewObject.h" - -namespace graphql::learn { - -class Review : public object::Review -{ -public: - explicit Review( - response::IntType stars, std::optional commentary) noexcept; - - service::FieldResult getStars(service::FieldParams&& params) const final; - service::FieldResult> getCommentary( - service::FieldParams&& params) const final; - -private: - const response::IntType stars_; - const std::optional commentary_; -}; - -} // namespace graphql::learn - -#endif // REVIEWDATA_H diff --git a/samples/today/CMakeLists.txt b/samples/today/CMakeLists.txt new file mode 100644 index 00000000..d4afd83f --- /dev/null +++ b/samples/today/CMakeLists.txt @@ -0,0 +1,65 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +# todaygraphql +add_subdirectory(schema) +add_library(todaygraphql STATIC TodayMock.cpp) +target_link_libraries(todaygraphql PUBLIC today_schema) +target_include_directories(todaygraphql PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +# todaygraphql_nointrospection +add_subdirectory(nointrospection) +add_library(todaygraphql_nointrospection STATIC TodayMock.cpp) +target_link_libraries(todaygraphql_nointrospection PUBLIC today_nointrospection_schema) +target_include_directories(todaygraphql_nointrospection PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +# sample +add_executable(sample sample.cpp) +target_link_libraries(sample PRIVATE + todaygraphql + graphqljson) + +# sample_nointrospection +add_executable(sample_nointrospection sample.cpp) +target_link_libraries(sample_nointrospection PRIVATE + todaygraphql_nointrospection + graphqljson) + +# benchmark +add_executable(benchmark benchmark.cpp) +target_link_libraries(benchmark PRIVATE + todaygraphql + graphqljson) + +# benchmark_nointrospection +add_executable(benchmark_nointrospection benchmark.cpp) +target_link_libraries(benchmark_nointrospection PRIVATE + todaygraphql_nointrospection + graphqljson) + +if(WIN32 AND BUILD_SHARED_LIBS) + add_custom_command(OUTPUT copied_sample_dlls + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $ + $ + $ + $ + ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E touch copied_sample_dlls + DEPENDS + graphqlservice + graphqlintrospection + graphqljson + graphqlpeg + graphqlresponse) + + add_custom_target(copy_today_sample_dlls DEPENDS copied_sample_dlls) + + add_dependencies(sample copy_today_sample_dlls) + add_dependencies(sample_nointrospection copy_today_sample_dlls) + add_dependencies(benchmark copy_today_sample_dlls) + add_dependencies(benchmark_nointrospection copy_today_sample_dlls) +endif() diff --git a/samples/today/TodayMock.cpp b/samples/today/TodayMock.cpp index 6bb29dc2..cd4f9fb5 100644 --- a/samples/today/TodayMock.cpp +++ b/samples/today/TodayMock.cpp @@ -3,7 +3,17 @@ #include "TodayMock.h" +#include "AppointmentConnectionObject.h" +#include "CompleteTaskPayloadObject.h" +#include "ExpensiveObject.h" +#include "FolderConnectionObject.h" +#include "NestedTypeObject.h" +#include "TaskConnectionObject.h" +#include "UnionTypeObject.h" + #include +#include +#include #include namespace graphql::today { @@ -11,22 +21,22 @@ namespace graphql::today { Appointment::Appointment( response::IdType&& id, std::string&& when, std::string&& subject, bool isNow) : _id(std::move(id)) - , _when(std::move(when)) - , _subject(std::move(subject)) + , _when(std::make_shared(std::move(when))) + , _subject(std::make_shared(std::move(subject))) , _isNow(isNow) { } Task::Task(response::IdType&& id, std::string&& title, bool isComplete) : _id(std::move(id)) - , _title(std::move(title)) + , _title(std::make_shared(std::move(title))) , _isComplete(isComplete) { } Folder::Folder(response::IdType&& id, std::string&& name, int unreadCount) : _id(std::move(id)) - , _name(std::move(name)) + , _name(std::make_shared(std::move(name))) , _unreadCount(unreadCount) { } @@ -39,7 +49,7 @@ Query::Query(appointmentsLoader&& getAppointments, tasksLoader&& getTasks, { } -void Query::loadAppointments(const std::shared_ptr& state) const +void Query::loadAppointments(const std::shared_ptr& state) { if (_getAppointments) { @@ -57,7 +67,7 @@ void Query::loadAppointments(const std::shared_ptr& state } std::shared_ptr Query::findAppointment( - const service::FieldParams& params, const response::IdType& id) const + const service::FieldParams& params, const response::IdType& id) { loadAppointments(params.state); @@ -72,7 +82,7 @@ std::shared_ptr Query::findAppointment( return nullptr; } -void Query::loadTasks(const std::shared_ptr& state) const +void Query::loadTasks(const std::shared_ptr& state) { if (_getTasks) { @@ -90,7 +100,7 @@ void Query::loadTasks(const std::shared_ptr& state) const } std::shared_ptr Query::findTask( - const service::FieldParams& params, const response::IdType& id) const + const service::FieldParams& params, const response::IdType& id) { loadTasks(params.state); @@ -105,7 +115,7 @@ std::shared_ptr Query::findTask( return nullptr; } -void Query::loadUnreadCounts(const std::shared_ptr& state) const +void Query::loadUnreadCounts(const std::shared_ptr& state) { if (_getUnreadCounts) { @@ -123,7 +133,7 @@ void Query::loadUnreadCounts(const std::shared_ptr& state } std::shared_ptr Query::findUnreadCount( - const service::FieldParams& params, const response::IdType& id) const + const service::FieldParams& params, const response::IdType& id) { loadUnreadCounts(params.state); @@ -138,36 +148,63 @@ std::shared_ptr Query::findUnreadCount( return nullptr; } -service::FieldResult> Query::getNode( - service::FieldParams&& params, response::IdType&& id) const +template +auto operator co_await(std::chrono::duration<_Rep, _Period> delay) { - std::promise> promise; + struct awaiter + { + const std::chrono::duration<_Rep, _Period> delay; + + constexpr bool await_ready() const + { + return true; + } + + void await_suspend(coro::coroutine_handle<> h) noexcept + { + h.resume(); + } + + void await_resume() + { + std::this_thread::sleep_for(delay); + } + }; + + return awaiter { delay }; +} + +service::AwaitableObject> Query::getNode( + service::FieldParams params, response::IdType id) +{ + // query { node(id: "ZmFrZVRhc2tJZA==") { ...on Task { title } } } + using namespace std::literals; + co_await 100ms; + auto appointment = findAppointment(params, id); if (appointment) { - promise.set_value(appointment); - return promise.get_future(); + co_return std::make_shared( + std::make_shared(std::move(appointment))); } auto task = findTask(params, id); if (task) { - promise.set_value(task); - return promise.get_future(); + co_return std::make_shared(std::make_shared(std::move(task))); } auto folder = findUnreadCount(params, id); if (folder) { - promise.set_value(folder); - return promise.get_future(); + co_return std::make_shared( + std::make_shared(std::move(folder))); } - promise.set_value(nullptr); - return promise.get_future(); + co_return nullptr; } template @@ -263,10 +300,10 @@ struct EdgeConstraints const vec_type& _objects; }; -service::FieldResult> Query::getAppointments( - service::FieldParams&& params, std::optional&& first, - std::optional&& after, std::optional&& last, - std::optional&& before) const +std::future> Query::getAppointments( + const service::FieldParams& params, std::optional first, + std::optional&& after, std::optional last, + std::optional&& before) { auto spThis = shared_from_this(); auto state = params.state; @@ -284,7 +321,7 @@ service::FieldResult> Query::getA lastWrapped, std::move(beforeWrapped)); - return std::static_pointer_cast(connection); + return std::make_shared(connection); }, std::move(first), std::move(after), @@ -292,10 +329,10 @@ service::FieldResult> Query::getA std::move(before)); } -service::FieldResult> Query::getTasks( - service::FieldParams&& params, std::optional&& first, - std::optional&& after, std::optional&& last, - std::optional&& before) const +std::future> Query::getTasks( + const service::FieldParams& params, std::optional first, + std::optional&& after, std::optional last, + std::optional&& before) { auto spThis = shared_from_this(); auto state = params.state; @@ -313,7 +350,7 @@ service::FieldResult> Query::getTasks( lastWrapped, std::move(beforeWrapped)); - return std::static_pointer_cast(connection); + return std::make_shared(connection); }, std::move(first), std::move(after), @@ -321,10 +358,10 @@ service::FieldResult> Query::getTasks( std::move(before)); } -service::FieldResult> Query::getUnreadCounts( - service::FieldParams&& params, std::optional&& first, - std::optional&& after, std::optional&& last, - std::optional&& before) const +std::future> Query::getUnreadCounts( + const service::FieldParams& params, std::optional first, + std::optional&& after, std::optional last, + std::optional&& before) { auto spThis = shared_from_this(); auto state = params.state; @@ -342,7 +379,7 @@ service::FieldResult> Query::getUnread lastWrapped, std::move(beforeWrapped)); - return std::static_pointer_cast(connection); + return std::make_shared(connection); }, std::move(first), std::move(after), @@ -350,97 +387,86 @@ service::FieldResult> Query::getUnread std::move(before)); } -service::FieldResult>> Query::getAppointmentsById( - service::FieldParams&& params, std::vector&& ids) const +std::vector> Query::getAppointmentsById( + const service::FieldParams& params, const std::vector& ids) { - std::promise>> promise; std::vector> result(ids.size()); std::transform(ids.cbegin(), ids.cend(), result.begin(), [this, ¶ms](const response::IdType& id) { - return std::static_pointer_cast(findAppointment(params, id)); + return std::make_shared(findAppointment(params, id)); }); - promise.set_value(std::move(result)); - return promise.get_future(); + return result; } -service::FieldResult>> Query::getTasksById( - service::FieldParams&& params, std::vector&& ids) const +std::vector> Query::getTasksById( + const service::FieldParams& params, const std::vector& ids) { - std::promise>> promise; std::vector> result(ids.size()); std::transform(ids.cbegin(), ids.cend(), result.begin(), [this, ¶ms](const response::IdType& id) { - return std::static_pointer_cast(findTask(params, id)); + return std::make_shared(findTask(params, id)); }); - promise.set_value(std::move(result)); - return promise.get_future(); + return result; } -service::FieldResult>> Query::getUnreadCountsById( - service::FieldParams&& params, std::vector&& ids) const +std::vector> Query::getUnreadCountsById( + const service::FieldParams& params, const std::vector& ids) { - std::promise>> promise; std::vector> result(ids.size()); std::transform(ids.cbegin(), ids.cend(), result.begin(), [this, ¶ms](const response::IdType& id) { - return std::static_pointer_cast(findUnreadCount(params, id)); + return std::make_shared(findUnreadCount(params, id)); }); - promise.set_value(std::move(result)); - return promise.get_future(); + return result; } -service::FieldResult> Query::getNested( - service::FieldParams&& params) const +std::shared_ptr Query::getNested(service::FieldParams&& params) { - std::promise> promise; - - promise.set_value(std::make_shared(std::move(params), 1)); - - return promise.get_future(); + return std::make_shared(std::make_shared(std::move(params), 1)); } -service::FieldResult>> Query::getExpensive( - service::FieldParams&& /*params*/) const +std::vector> Query::getExpensive() { std::vector> result(Expensive::count); for (auto& entry : result) { - entry = std::make_shared(); + entry = std::make_shared(std::make_shared()); } return result; } -service::FieldResult Query::getTestTaskState(service::FieldParams&& /*params*/) const +TaskState Query::getTestTaskState() { return TaskState::Unassigned; } -service::FieldResult>> Query::getAnyType( - service::FieldParams&& params, std::vector&& idsArg) const +std::vector> Query::getAnyType( + const service::FieldParams& params, const std::vector&) { loadAppointments(params.state); - std::vector> result(_appointments.size()); + std::vector> result(_appointments.size()); std::transform(_appointments.cbegin(), _appointments.cend(), result.begin(), - [](const std::shared_ptr& appointment) noexcept { - return std::static_pointer_cast(appointment); + [](const auto& appointment) noexcept { + return std::make_shared( + std::make_shared(appointment)); }); return result; @@ -451,25 +477,20 @@ Mutation::Mutation(completeTaskMutation&& mutateCompleteTask) { } -service::FieldResult> Mutation::applyCompleteTask( - service::FieldParams&& params, CompleteTaskInput&& input) const +std::shared_ptr Mutation::applyCompleteTask( + CompleteTaskInput&& input) noexcept { - std::promise> promise; - - promise.set_value(_mutateCompleteTask(std::move(input))); - - return promise.get_future(); + return std::make_shared(_mutateCompleteTask(std::move(input))); } -std::optional Mutation::_setFloat = std::nullopt; +std::optional Mutation::_setFloat = std::nullopt; double Mutation::getFloat() noexcept { return *_setFloat; } -service::FieldResult Mutation::applySetFloat( - service::FieldParams&& params, response::FloatType&& valueArg) const +double Mutation::applySetFloat(double valueArg) noexcept { _setFloat = std::make_optional(valueArg); return valueArg; @@ -480,33 +501,32 @@ std::stack NestedType::_capturedParams; NestedType::NestedType(service::FieldParams&& params, int depth) : depth(depth) { - _capturedParams.push({ response::Value(params.operationDirectives), - response::Value(params.fragmentDefinitionDirectives), - response::Value(params.fragmentSpreadDirectives), - response::Value(params.inlineFragmentDirectives), + _capturedParams.push({ { params.operationDirectives }, + params.fragmentDefinitionDirectives->empty() + ? service::Directives {} + : service::Directives { params.fragmentDefinitionDirectives->front().get() }, + params.fragmentSpreadDirectives->empty() + ? service::Directives {} + : service::Directives { params.fragmentSpreadDirectives->front() }, + params.inlineFragmentDirectives->empty() + ? service::Directives {} + : service::Directives { params.inlineFragmentDirectives->front() }, std::move(params.fieldDirectives) }); } -service::FieldResult NestedType::getDepth(service::FieldParams&& params) const +int NestedType::getDepth() const noexcept { - std::promise promise; - - promise.set_value(depth); - - return promise.get_future(); + return depth; } -service::FieldResult> NestedType::getNested( - service::FieldParams&& params) const +std::shared_ptr NestedType::getNested( + service::FieldParams&& params) const noexcept { - std::promise> promise; - - promise.set_value(std::make_shared(std::move(params), depth + 1)); - - return promise.get_future(); + return std::make_shared( + std::make_shared(std::move(params), depth + 1)); } -std::stack NestedType::getCapturedParams() +std::stack NestedType::getCapturedParams() noexcept { auto result = std::move(_capturedParams); @@ -540,11 +560,11 @@ Expensive::~Expensive() --instances; } -service::FieldResult Expensive::getOrder(service::FieldParams&& params) const +std::future Expensive::getOrder(const service::FieldParams& params) const noexcept { return std::async( - params.launch, - [](bool blockAsync, response::IntType instanceOrder) noexcept { + params.launch.await_ready() ? std::launch::deferred : std::launch::async, + [](bool blockAsync, int instanceOrder) noexcept { if (blockAsync) { // Block all of the Expensive objects in async mode until the count is reached. @@ -564,8 +584,8 @@ service::FieldResult Expensive::getOrder(service::FieldParams return instanceOrder; }, - params.launch == std::launch::async, - static_cast(order)); + !params.launch.await_ready(), + static_cast(order)); } EmptyOperations::EmptyOperations() diff --git a/samples/today/TodayMock.h b/samples/today/TodayMock.h index c9ccfe83..c9bd3c37 100644 --- a/samples/today/TodayMock.h +++ b/samples/today/TodayMock.h @@ -6,13 +6,22 @@ #ifndef TODAYMOCK_H #define TODAYMOCK_H -#ifdef IMPL_SEPARATE_TODAY -#include "TodayObjects.h" -#else #include "TodaySchema.h" -#endif + +#include "AppointmentEdgeObject.h" +#include "AppointmentObject.h" +#include "FolderEdgeObject.h" +#include "FolderObject.h" +#include "MutationObject.h" +#include "NodeObject.h" +#include "PageInfoObject.h" +#include "QueryObject.h" +#include "SubscriptionObject.h" +#include "TaskEdgeObject.h" +#include "TaskObject.h" #include +#include #include namespace graphql::today { @@ -40,7 +49,7 @@ class Task; class Folder; class Expensive; -class Query : public object::Query +class Query : public std::enable_shared_from_this { public: using appointmentsLoader = std::function>()>; @@ -50,57 +59,54 @@ class Query : public object::Query explicit Query(appointmentsLoader&& getAppointments, tasksLoader&& getTasks, unreadCountsLoader&& getUnreadCounts); - service::FieldResult> getNode( - service::FieldParams&& params, response::IdType&& id) const final; - service::FieldResult> getAppointments( - service::FieldParams&& params, std::optional&& first, - std::optional&& after, std::optional&& last, - std::optional&& before) const final; - service::FieldResult> getTasks( - service::FieldParams&& params, std::optional&& first, - std::optional&& after, std::optional&& last, - std::optional&& before) const final; - service::FieldResult> getUnreadCounts( - service::FieldParams&& params, std::optional&& first, - std::optional&& after, std::optional&& last, - std::optional&& before) const final; - service::FieldResult>> getAppointmentsById( - service::FieldParams&& params, std::vector&& ids) const final; - service::FieldResult>> getTasksById( - service::FieldParams&& params, std::vector&& ids) const final; - service::FieldResult>> getUnreadCountsById( - service::FieldParams&& params, std::vector&& ids) const final; - service::FieldResult> getNested( - service::FieldParams&& params) const final; - service::FieldResult>> getExpensive( - service::FieldParams&& params) const final; - service::FieldResult getTestTaskState(service::FieldParams&& params) const final; - service::FieldResult>> getAnyType( - service::FieldParams&& params, std::vector&& idsArg) const final; + service::AwaitableObject> getNode( + service::FieldParams params, response::IdType id); + std::future> getAppointments( + const service::FieldParams& params, std::optional first, + std::optional&& after, std::optional last, + std::optional&& before); + std::future> getTasks( + const service::FieldParams& params, std::optional first, + std::optional&& after, std::optional last, + std::optional&& before); + std::future> getUnreadCounts( + const service::FieldParams& params, std::optional first, + std::optional&& after, std::optional last, + std::optional&& before); + std::vector> getAppointmentsById( + const service::FieldParams& params, const std::vector& ids); + std::vector> getTasksById( + const service::FieldParams& params, const std::vector& ids); + std::vector> getUnreadCountsById( + const service::FieldParams& params, const std::vector& ids); + std::shared_ptr getNested(service::FieldParams&& params); + std::vector> getExpensive(); + TaskState getTestTaskState(); + std::vector> getAnyType( + const service::FieldParams& params, const std::vector& ids); private: std::shared_ptr findAppointment( - const service::FieldParams& params, const response::IdType& id) const; - std::shared_ptr findTask( - const service::FieldParams& params, const response::IdType& id) const; + const service::FieldParams& params, const response::IdType& id); + std::shared_ptr findTask(const service::FieldParams& params, const response::IdType& id); std::shared_ptr findUnreadCount( - const service::FieldParams& params, const response::IdType& id) const; + const service::FieldParams& params, const response::IdType& id); // Lazy load the fields in each query - void loadAppointments(const std::shared_ptr& state) const; - void loadTasks(const std::shared_ptr& state) const; - void loadUnreadCounts(const std::shared_ptr& state) const; + void loadAppointments(const std::shared_ptr& state); + void loadTasks(const std::shared_ptr& state); + void loadUnreadCounts(const std::shared_ptr& state); - mutable appointmentsLoader _getAppointments; - mutable tasksLoader _getTasks; - mutable unreadCountsLoader _getUnreadCounts; + appointmentsLoader _getAppointments; + tasksLoader _getTasks; + unreadCountsLoader _getUnreadCounts; - mutable std::vector> _appointments; - mutable std::vector> _tasks; - mutable std::vector> _unreadCounts; + std::vector> _appointments; + std::vector> _tasks; + std::vector> _unreadCounts; }; -class PageInfo : public object::PageInfo +class PageInfo { public: explicit PageInfo(bool hasNextPage, bool hasPreviousPage) @@ -109,12 +115,12 @@ class PageInfo : public object::PageInfo { } - service::FieldResult getHasNextPage(service::FieldParams&&) const final + bool getHasNextPage() const noexcept { return _hasNextPage; } - service::FieldResult getHasPreviousPage(service::FieldParams&&) const final + bool getHasPreviousPage() const noexcept { return _hasPreviousPage; } @@ -124,53 +130,51 @@ class PageInfo : public object::PageInfo const bool _hasPreviousPage; }; -class Appointment : public object::Appointment +class Appointment { public: explicit Appointment( response::IdType&& id, std::string&& when, std::string&& subject, bool isNow); // EdgeConstraints accessor - const response::IdType& id() const + const response::IdType& id() const noexcept { return _id; } - service::FieldResult getId(service::FieldParams&&) const final + service::AwaitableScalar getId() const noexcept { return _id; } - service::FieldResult> getWhen(service::FieldParams&&) const final + std::shared_ptr getWhen() const noexcept { - return std::make_optional(std::string(_when)); + return _when; } - service::FieldResult> getSubject( - service::FieldParams&&) const final + std::shared_ptr getSubject() const noexcept { - return std::make_optional(_subject); + return _subject; } - service::FieldResult getIsNow(service::FieldParams&&) const final + bool getIsNow() const noexcept { return _isNow; } - service::FieldResult> getForceError( - service::FieldParams&&) const final + std::optional getForceError() const { throw std::runtime_error(R"ex(this error was forced)ex"); } private: response::IdType _id; - std::string _when; - std::string _subject; + std::shared_ptr _when; + std::shared_ptr _subject; bool _isNow; }; -class AppointmentEdge : public object::AppointmentEdge +class AppointmentEdge { public: explicit AppointmentEdge(std::shared_ptr appointment) @@ -178,22 +182,21 @@ class AppointmentEdge : public object::AppointmentEdge { } - service::FieldResult> getNode( - service::FieldParams&&) const final + std::shared_ptr getNode() const noexcept { - return std::static_pointer_cast(_appointment); + return std::make_shared(_appointment); } - service::FieldResult getCursor(service::FieldParams&& params) const final + service::AwaitableScalar getCursor() const { - return response::Value(_appointment->getId(std::move(params)).get()); + co_return response::Value(co_await _appointment->getId()); } private: std::shared_ptr _appointment; }; -class AppointmentConnection : public object::AppointmentConnection +class AppointmentConnection { public: explicit AppointmentConnection(bool hasNextPage, bool hasPreviousPage, @@ -203,14 +206,12 @@ class AppointmentConnection : public object::AppointmentConnection { } - service::FieldResult> getPageInfo( - service::FieldParams&&) const final + std::shared_ptr getPageInfo() const noexcept { - return _pageInfo; + return std::make_shared(_pageInfo); } - service::FieldResult>>> - getEdges(service::FieldParams&&) const final + std::optional>> getEdges() const noexcept { auto result = std::make_optional>>( _appointments.size()); @@ -219,10 +220,11 @@ class AppointmentConnection : public object::AppointmentConnection _appointments.cend(), result->begin(), [](const std::shared_ptr& node) { - return std::make_shared(node); + return std::make_shared( + std::make_shared(node)); }); - return { std::move(result) }; + return result; } private: @@ -230,7 +232,7 @@ class AppointmentConnection : public object::AppointmentConnection std::vector> _appointments; }; -class Task : public object::Task +class Task { public: explicit Task(response::IdType&& id, std::string&& title, bool isComplete); @@ -241,30 +243,29 @@ class Task : public object::Task return _id; } - service::FieldResult getId(service::FieldParams&&) const final + service::AwaitableScalar getId() const noexcept { return _id; } - service::FieldResult> getTitle( - service::FieldParams&&) const final + std::shared_ptr getTitle() const noexcept { - return std::make_optional(_title); + return _title; } - service::FieldResult getIsComplete(service::FieldParams&&) const final + bool getIsComplete() const noexcept { return _isComplete; } private: response::IdType _id; - std::string _title; + std::shared_ptr _title; bool _isComplete; TaskState _state = TaskState::New; }; -class TaskEdge : public object::TaskEdge +class TaskEdge { public: explicit TaskEdge(std::shared_ptr task) @@ -272,21 +273,21 @@ class TaskEdge : public object::TaskEdge { } - service::FieldResult> getNode(service::FieldParams&&) const final + std::shared_ptr getNode() const noexcept { - return std::static_pointer_cast(_task); + return std::make_shared(_task); } - service::FieldResult getCursor(service::FieldParams&& params) const final + service::AwaitableScalar getCursor() const noexcept { - return response::Value(_task->getId(std::move(params)).get()); + co_return response::Value(co_await _task->getId()); } private: std::shared_ptr _task; }; -class TaskConnection : public object::TaskConnection +class TaskConnection { public: explicit TaskConnection( @@ -296,14 +297,12 @@ class TaskConnection : public object::TaskConnection { } - service::FieldResult> getPageInfo( - service::FieldParams&&) const final + std::shared_ptr getPageInfo() const noexcept { - return _pageInfo; + return std::make_shared(_pageInfo); } - service::FieldResult>>> getEdges( - service::FieldParams&&) const final + std::optional>> getEdges() const noexcept { auto result = std::make_optional>>(_tasks.size()); @@ -312,10 +311,10 @@ class TaskConnection : public object::TaskConnection _tasks.cend(), result->begin(), [](const std::shared_ptr& node) { - return std::make_shared(node); + return std::make_shared(std::make_shared(node)); }); - return { std::move(result) }; + return result; } private: @@ -323,40 +322,39 @@ class TaskConnection : public object::TaskConnection std::vector> _tasks; }; -class Folder : public object::Folder +class Folder { public: explicit Folder(response::IdType&& id, std::string&& name, int unreadCount); // EdgeConstraints accessor - const response::IdType& id() const + const response::IdType& id() const noexcept { return _id; } - service::FieldResult getId(service::FieldParams&&) const final + service::AwaitableScalar getId() const noexcept { return _id; } - service::FieldResult> getName( - service::FieldParams&&) const final + std::shared_ptr getName() const noexcept { - return std::make_optional(_name); + return _name; } - service::FieldResult getUnreadCount(service::FieldParams&&) const final + int getUnreadCount() const noexcept { return _unreadCount; } private: response::IdType _id; - std::string _name; + std::shared_ptr _name; int _unreadCount; }; -class FolderEdge : public object::FolderEdge +class FolderEdge { public: explicit FolderEdge(std::shared_ptr folder) @@ -364,22 +362,21 @@ class FolderEdge : public object::FolderEdge { } - service::FieldResult> getNode( - service::FieldParams&&) const final + std::shared_ptr getNode() const noexcept { - return std::static_pointer_cast(_folder); + return std::make_shared(_folder); } - service::FieldResult getCursor(service::FieldParams&& params) const final + service::AwaitableScalar getCursor() const noexcept { - return response::Value(_folder->getId(std::move(params)).get()); + co_return response::Value(co_await _folder->getId()); } private: std::shared_ptr _folder; }; -class FolderConnection : public object::FolderConnection +class FolderConnection { public: explicit FolderConnection( @@ -389,14 +386,12 @@ class FolderConnection : public object::FolderConnection { } - service::FieldResult> getPageInfo( - service::FieldParams&&) const final + std::shared_ptr getPageInfo() const noexcept { - return _pageInfo; + return std::make_shared(_pageInfo); } - service::FieldResult>>> getEdges( - service::FieldParams&&) const final + std::optional>> getEdges() const noexcept { auto result = std::make_optional>>(_folders.size()); @@ -405,10 +400,10 @@ class FolderConnection : public object::FolderConnection _folders.cend(), result->begin(), [](const std::shared_ptr& node) { - return std::make_shared(node); + return std::make_shared(std::make_shared(node)); }); - return { std::move(result) }; + return result; } private: @@ -416,34 +411,32 @@ class FolderConnection : public object::FolderConnection std::vector> _folders; }; -class CompleteTaskPayload : public object::CompleteTaskPayload +class CompleteTaskPayload { public: explicit CompleteTaskPayload( - std::shared_ptr task, std::optional&& clientMutationId) + std::shared_ptr task, std::optional&& clientMutationId) : _task(std::move(task)) , _clientMutationId(std::move(clientMutationId)) { } - service::FieldResult> getTask(service::FieldParams&&) const final + std::shared_ptr getTask() const noexcept { - return std::static_pointer_cast(_task); + return std::make_shared(_task); } - service::FieldResult> getClientMutationId( - service::FieldParams&&) const final + const std::optional& getClientMutationId() const noexcept { - return { _clientMutationId ? std::make_optional(*_clientMutationId) - : std::nullopt }; + return _clientMutationId; } private: std::shared_ptr _task; - std::optional _clientMutationId; + std::optional _clientMutationId; }; -class Mutation : public object::Mutation +class Mutation { public: using completeTaskMutation = @@ -453,35 +446,32 @@ class Mutation : public object::Mutation static double getFloat() noexcept; - service::FieldResult> applyCompleteTask( - service::FieldParams&& params, CompleteTaskInput&& input) const final; - service::FieldResult applySetFloat( - service::FieldParams&& params, response::FloatType&& valueArg) const final; + std::shared_ptr applyCompleteTask( + CompleteTaskInput&& input) noexcept; + double applySetFloat(double valueArg) noexcept; private: completeTaskMutation _mutateCompleteTask; - static std::optional _setFloat; + static std::optional _setFloat; }; -class Subscription : public object::Subscription +class Subscription { public: explicit Subscription() = default; - service::FieldResult> getNextAppointmentChange( - service::FieldParams&&) const final + std::shared_ptr getNextAppointmentChange() const { throw std::runtime_error("Unexpected call to getNextAppointmentChange"); } - service::FieldResult> getNodeChange( - service::FieldParams&&, response::IdType&&) const final + std::shared_ptr getNodeChange(const response::IdType&) const { throw std::runtime_error("Unexpected call to getNodeChange"); } }; -class NextAppointmentChange : public object::Subscription +class NextAppointmentChange { public: using nextAppointmentChange = @@ -510,8 +500,8 @@ class NextAppointmentChange : public object::Subscription } } - service::FieldResult> getNextAppointmentChange( - service::FieldParams&& params) const final + std::shared_ptr getNextAppointmentChange( + const service::FieldParams& params) const { switch (params.resolverContext) { @@ -537,11 +527,10 @@ class NextAppointmentChange : public object::Subscription throw std::runtime_error("Unexpected ResolverContext"); } - return std::static_pointer_cast(_changeNextAppointment(params.state)); + return std::make_shared(_changeNextAppointment(params.state)); } - service::FieldResult> getNodeChange( - service::FieldParams&&, response::IdType&&) const final + std::shared_ptr getNodeChange(const response::IdType&) const { throw std::runtime_error("Unexpected call to getNodeChange"); } @@ -554,10 +543,10 @@ class NextAppointmentChange : public object::Subscription static size_t _notifyUnsubscribeCount; }; -class NodeChange : public object::Subscription +class NodeChange { public: - using nodeChange = std::function( + using nodeChange = std::function( const std::shared_ptr&, response::IdType&&)>; explicit NodeChange(nodeChange&& changeNode) @@ -565,17 +554,15 @@ class NodeChange : public object::Subscription { } - service::FieldResult> getNextAppointmentChange( - service::FieldParams&&) const final + std::shared_ptr getNextAppointmentChange() const { throw std::runtime_error("Unexpected call to getNextAppointmentChange"); } - service::FieldResult> getNodeChange( - service::FieldParams&& params, response::IdType&& idArg) const final + std::shared_ptr getNodeChange( + const service::FieldParams& params, response::IdType&& idArg) const { - return std::static_pointer_cast( - _changeNode(params.state, std::move(idArg))); + return _changeNode(params.state, std::move(idArg)); } private: @@ -585,25 +572,24 @@ class NodeChange : public object::Subscription struct CapturedParams { // Copied in the constructor - const response::Value operationDirectives; - const response::Value fragmentDefinitionDirectives; - const response::Value fragmentSpreadDirectives; - const response::Value inlineFragmentDirectives; + const service::Directives operationDirectives; + const service::Directives fragmentDefinitionDirectives; + const service::Directives fragmentSpreadDirectives; + const service::Directives inlineFragmentDirectives; // Moved in the constructor - const response::Value fieldDirectives; + const service::Directives fieldDirectives; }; -class NestedType : public object::NestedType +class NestedType { public: explicit NestedType(service::FieldParams&& params, int depth); - service::FieldResult getDepth(service::FieldParams&& params) const final; - service::FieldResult> getNested( - service::FieldParams&& params) const final; + int getDepth() const noexcept; + std::shared_ptr getNested(service::FieldParams&& params) const noexcept; - static std::stack getCapturedParams(); + static std::stack getCapturedParams() noexcept; private: static std::stack _capturedParams; @@ -612,7 +598,7 @@ class NestedType : public object::NestedType const int depth; }; -class Expensive : public object::Expensive +class Expensive { public: static bool Reset() noexcept; @@ -620,7 +606,7 @@ class Expensive : public object::Expensive explicit Expensive(); ~Expensive(); - service::FieldResult getOrder(service::FieldParams&& params) const final; + std::future getOrder(const service::FieldParams& params) const noexcept; static constexpr size_t count = 5; static std::mutex testMutex; diff --git a/samples/today/benchmark.cpp b/samples/today/benchmark.cpp index acb6c354..3733ba98 100644 --- a/samples/today/benchmark.cpp +++ b/samples/today/benchmark.cpp @@ -157,8 +157,7 @@ int main(int argc, char** argv) service->validate(query); const auto startResolve = std::chrono::steady_clock::now(); - auto response = - service->resolve(nullptr, query, "", response::Value(response::Type::Map)).get(); + auto response = service->resolve({ query }).get(); const auto startToJson = std::chrono::steady_clock::now(); response::toJSON(std::move(response)); diff --git a/samples/today/nointrospection/AppointmentConnectionObject.cpp b/samples/today/nointrospection/AppointmentConnectionObject.cpp new file mode 100644 index 00000000..19842a49 --- /dev/null +++ b/samples/today/nointrospection/AppointmentConnectionObject.cpp @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "AppointmentConnectionObject.h" +#include "PageInfoObject.h" +#include "AppointmentEdgeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +AppointmentConnection::AppointmentConnection(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames AppointmentConnection::getTypeNames() const noexcept +{ + return { + R"gql(AppointmentConnection)gql"sv + }; +} + +service::ResolverMap AppointmentConnection::getResolvers() const noexcept +{ + return { + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void AppointmentConnection::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void AppointmentConnection::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver AppointmentConnection::resolveEdges(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver AppointmentConnection::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(AppointmentConnection)gql" }, std::move(params)); +} + +} // namespace object + +void AddAppointmentConnectionDetails(const std::shared_ptr& typeAppointmentConnection, const std::shared_ptr& schema) +{ + typeAppointmentConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PageInfo)gql"sv))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(AppointmentEdge)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/AppointmentConnectionObject.h b/samples/today/nointrospection/AppointmentConnectionObject.h new file mode 100644 index 00000000..8c065063 --- /dev/null +++ b/samples/today/nointrospection/AppointmentConnectionObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef APPOINTMENTCONNECTIONOBJECT_H +#define APPOINTMENTCONNECTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::AppointmentConnectionHas { + +template +concept getPageInfoWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getPageInfo(std::move(params)) } }; +}; + +template +concept getPageInfo = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getPageInfo() } }; +}; + +template +concept getEdgesWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject>>> { impl.getEdges(std::move(params)) } }; +}; + +template +concept getEdges = requires (TImpl impl) +{ + { service::AwaitableObject>>> { impl.getEdges() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::AppointmentConnectionHas + +class AppointmentConnection + : public service::Object +{ +private: + service::AwaitableResolver resolvePageInfo(service::ResolverParams&& params) const; + service::AwaitableResolver resolveEdges(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getPageInfo(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>>> getEdges(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getPageInfo(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentConnectionHas::getPageInfoWithParams) + { + return { _pimpl->getPageInfo(std::move(params)) }; + } + else if constexpr (methods::AppointmentConnectionHas::getPageInfo) + { + return { _pimpl->getPageInfo() }; + } + else + { + throw std::runtime_error(R"ex(AppointmentConnection::getPageInfo is not implemented)ex"); + } + } + + service::AwaitableObject>>> getEdges(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentConnectionHas::getEdgesWithParams) + { + return { _pimpl->getEdges(std::move(params)) }; + } + else if constexpr (methods::AppointmentConnectionHas::getEdges) + { + return { _pimpl->getEdges() }; + } + else + { + throw std::runtime_error(R"ex(AppointmentConnection::getEdges is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentConnectionHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentConnectionHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + AppointmentConnection(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + AppointmentConnection(std::shared_ptr pimpl) noexcept + : AppointmentConnection { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // APPOINTMENTCONNECTIONOBJECT_H diff --git a/samples/today/nointrospection/AppointmentEdgeObject.cpp b/samples/today/nointrospection/AppointmentEdgeObject.cpp new file mode 100644 index 00000000..ea507e43 --- /dev/null +++ b/samples/today/nointrospection/AppointmentEdgeObject.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "AppointmentEdgeObject.h" +#include "AppointmentObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +AppointmentEdge::AppointmentEdge(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames AppointmentEdge::getTypeNames() const noexcept +{ + return { + R"gql(AppointmentEdge)gql"sv + }; +} + +service::ResolverMap AppointmentEdge::getResolvers() const noexcept +{ + return { + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void AppointmentEdge::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void AppointmentEdge::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver AppointmentEdge::resolveNode(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver AppointmentEdge::resolveCursor(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver AppointmentEdge::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(AppointmentEdge)gql" }, std::move(params)); +} + +} // namespace object + +void AddAppointmentEdgeDetails(const std::shared_ptr& typeAppointmentEdge, const std::shared_ptr& schema) +{ + typeAppointmentEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Appointment)gql"sv)), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ItemCursor)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/AppointmentEdgeObject.h b/samples/today/nointrospection/AppointmentEdgeObject.h new file mode 100644 index 00000000..205d2d3f --- /dev/null +++ b/samples/today/nointrospection/AppointmentEdgeObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef APPOINTMENTEDGEOBJECT_H +#define APPOINTMENTEDGEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::AppointmentEdgeHas { + +template +concept getNodeWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNode(std::move(params)) } }; +}; + +template +concept getNode = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNode() } }; +}; + +template +concept getCursorWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getCursor(std::move(params)) } }; +}; + +template +concept getCursor = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getCursor() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::AppointmentEdgeHas + +class AppointmentEdge + : public service::Object +{ +private: + service::AwaitableResolver resolveNode(service::ResolverParams&& params) const; + service::AwaitableResolver resolveCursor(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getNode(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getCursor(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getNode(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentEdgeHas::getNodeWithParams) + { + return { _pimpl->getNode(std::move(params)) }; + } + else if constexpr (methods::AppointmentEdgeHas::getNode) + { + return { _pimpl->getNode() }; + } + else + { + throw std::runtime_error(R"ex(AppointmentEdge::getNode is not implemented)ex"); + } + } + + service::AwaitableScalar getCursor(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentEdgeHas::getCursorWithParams) + { + return { _pimpl->getCursor(std::move(params)) }; + } + else if constexpr (methods::AppointmentEdgeHas::getCursor) + { + return { _pimpl->getCursor() }; + } + else + { + throw std::runtime_error(R"ex(AppointmentEdge::getCursor is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentEdgeHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentEdgeHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + AppointmentEdge(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + AppointmentEdge(std::shared_ptr pimpl) noexcept + : AppointmentEdge { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // APPOINTMENTEDGEOBJECT_H diff --git a/samples/today/nointrospection/AppointmentObject.cpp b/samples/today/nointrospection/AppointmentObject.cpp new file mode 100644 index 00000000..474ee49b --- /dev/null +++ b/samples/today/nointrospection/AppointmentObject.cpp @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "AppointmentObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Appointment::Appointment(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Appointment::getTypeNames() const noexcept +{ + return { + R"gql(Node)gql"sv, + R"gql(UnionType)gql"sv, + R"gql(Appointment)gql"sv + }; +} + +service::ResolverMap Appointment::getResolvers() const noexcept +{ + return { + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(when)gql"sv, [this](service::ResolverParams&& params) { return resolveWhen(std::move(params)); } }, + { R"gql(isNow)gql"sv, [this](service::ResolverParams&& params) { return resolveIsNow(std::move(params)); } }, + { R"gql(subject)gql"sv, [this](service::ResolverParams&& params) { return resolveSubject(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(forceError)gql"sv, [this](service::ResolverParams&& params) { return resolveForceError(std::move(params)); } } + }; +} + +void Appointment::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Appointment::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Appointment::resolveId(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Appointment::resolveWhen(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getWhen(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Appointment::resolveSubject(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getSubject(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Appointment::resolveIsNow(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getIsNow(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Appointment::resolveForceError(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getForceError(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Appointment::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Appointment)gql" }, std::move(params)); +} + +} // namespace object + +void AddAppointmentDetails(const std::shared_ptr& typeAppointment, const std::shared_ptr& schema) +{ + typeAppointment->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) + }); + typeAppointment->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))), + schema::Field::Make(R"gql(when)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(DateTime)gql"sv)), + schema::Field::Make(R"gql(subject)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(isNow)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))), + schema::Field::Make(R"gql(forceError)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/AppointmentObject.h b/samples/today/nointrospection/AppointmentObject.h new file mode 100644 index 00000000..22817647 --- /dev/null +++ b/samples/today/nointrospection/AppointmentObject.h @@ -0,0 +1,264 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef APPOINTMENTOBJECT_H +#define APPOINTMENTOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace implements { + +template +concept AppointmentIs = std::is_same_v || std::is_same_v; + +} // namespace implements + +namespace methods::AppointmentHas { + +template +concept getIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getId(std::move(params)) } }; +}; + +template +concept getId = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getId() } }; +}; + +template +concept getWhenWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getWhen(std::move(params)) } }; +}; + +template +concept getWhen = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getWhen() } }; +}; + +template +concept getSubjectWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getSubject(std::move(params)) } }; +}; + +template +concept getSubject = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getSubject() } }; +}; + +template +concept getIsNowWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getIsNow(std::move(params)) } }; +}; + +template +concept getIsNow = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getIsNow() } }; +}; + +template +concept getForceErrorWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getForceError(std::move(params)) } }; +}; + +template +concept getForceError = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getForceError() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::AppointmentHas + +class Appointment + : public service::Object +{ +private: + service::AwaitableResolver resolveId(service::ResolverParams&& params) const; + service::AwaitableResolver resolveWhen(service::ResolverParams&& params) const; + service::AwaitableResolver resolveSubject(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIsNow(service::ResolverParams&& params) const; + service::AwaitableResolver resolveForceError(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getId(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getWhen(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getSubject(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getIsNow(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getForceError(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getId(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentHas::getIdWithParams) + { + return { _pimpl->getId(std::move(params)) }; + } + else if constexpr (methods::AppointmentHas::getId) + { + return { _pimpl->getId() }; + } + else + { + throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); + } + } + + service::AwaitableScalar> getWhen(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentHas::getWhenWithParams) + { + return { _pimpl->getWhen(std::move(params)) }; + } + else if constexpr (methods::AppointmentHas::getWhen) + { + return { _pimpl->getWhen() }; + } + else + { + throw std::runtime_error(R"ex(Appointment::getWhen is not implemented)ex"); + } + } + + service::AwaitableScalar> getSubject(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentHas::getSubjectWithParams) + { + return { _pimpl->getSubject(std::move(params)) }; + } + else if constexpr (methods::AppointmentHas::getSubject) + { + return { _pimpl->getSubject() }; + } + else + { + throw std::runtime_error(R"ex(Appointment::getSubject is not implemented)ex"); + } + } + + service::AwaitableScalar getIsNow(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentHas::getIsNowWithParams) + { + return { _pimpl->getIsNow(std::move(params)) }; + } + else if constexpr (methods::AppointmentHas::getIsNow) + { + return { _pimpl->getIsNow() }; + } + else + { + throw std::runtime_error(R"ex(Appointment::getIsNow is not implemented)ex"); + } + } + + service::AwaitableScalar> getForceError(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentHas::getForceErrorWithParams) + { + return { _pimpl->getForceError(std::move(params)) }; + } + else if constexpr (methods::AppointmentHas::getForceError) + { + return { _pimpl->getForceError() }; + } + else + { + throw std::runtime_error(R"ex(Appointment::getForceError is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Appointment(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Node; + + // Unions which include this type + friend UnionType; + + template + static constexpr bool implements() noexcept + { + return implements::AppointmentIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Appointment(std::shared_ptr pimpl) noexcept + : Appointment { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // APPOINTMENTOBJECT_H diff --git a/samples/today/nointrospection/CMakeLists.txt b/samples/today/nointrospection/CMakeLists.txt new file mode 100644 index 00000000..723d5368 --- /dev/null +++ b/samples/today/nointrospection/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +# Normally this would be handled by find_package(cppgraphqlgen CONFIG). +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/cppgraphqlgen-functions.cmake) + +if(GRAPHQL_UPDATE_SAMPLES) + update_graphql_schema_files(today_nointrospection ../schema.today.graphql Today today --stubs --no-introspection) +endif() + +add_graphql_schema_no_introspection_target(today_nointrospection) diff --git a/samples/today/nointrospection/CompleteTaskPayloadObject.cpp b/samples/today/nointrospection/CompleteTaskPayloadObject.cpp new file mode 100644 index 00000000..bccfeca8 --- /dev/null +++ b/samples/today/nointrospection/CompleteTaskPayloadObject.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "CompleteTaskPayloadObject.h" +#include "TaskObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +CompleteTaskPayload::CompleteTaskPayload(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames CompleteTaskPayload::getTypeNames() const noexcept +{ + return { + R"gql(CompleteTaskPayload)gql"sv + }; +} + +service::ResolverMap CompleteTaskPayload::getResolvers() const noexcept +{ + return { + { R"gql(task)gql"sv, [this](service::ResolverParams&& params) { return resolveTask(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(clientMutationId)gql"sv, [this](service::ResolverParams&& params) { return resolveClientMutationId(std::move(params)); } } + }; +} + +void CompleteTaskPayload::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void CompleteTaskPayload::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver CompleteTaskPayload::resolveTask(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getClientMutationId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(CompleteTaskPayload)gql" }, std::move(params)); +} + +} // namespace object + +void AddCompleteTaskPayloadDetails(const std::shared_ptr& typeCompleteTaskPayload, const std::shared_ptr& schema) +{ + typeCompleteTaskPayload->AddFields({ + schema::Field::Make(R"gql(task)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Task)gql"sv)), + schema::Field::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/CompleteTaskPayloadObject.h b/samples/today/nointrospection/CompleteTaskPayloadObject.h new file mode 100644 index 00000000..3385815a --- /dev/null +++ b/samples/today/nointrospection/CompleteTaskPayloadObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef COMPLETETASKPAYLOADOBJECT_H +#define COMPLETETASKPAYLOADOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::CompleteTaskPayloadHas { + +template +concept getTaskWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getTask(std::move(params)) } }; +}; + +template +concept getTask = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getTask() } }; +}; + +template +concept getClientMutationIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getClientMutationId(std::move(params)) } }; +}; + +template +concept getClientMutationId = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getClientMutationId() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::CompleteTaskPayloadHas + +class CompleteTaskPayload + : public service::Object +{ +private: + service::AwaitableResolver resolveTask(service::ResolverParams&& params) const; + service::AwaitableResolver resolveClientMutationId(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getTask(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getClientMutationId(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getTask(service::FieldParams&& params) const final + { + if constexpr (methods::CompleteTaskPayloadHas::getTaskWithParams) + { + return { _pimpl->getTask(std::move(params)) }; + } + else if constexpr (methods::CompleteTaskPayloadHas::getTask) + { + return { _pimpl->getTask() }; + } + else + { + throw std::runtime_error(R"ex(CompleteTaskPayload::getTask is not implemented)ex"); + } + } + + service::AwaitableScalar> getClientMutationId(service::FieldParams&& params) const final + { + if constexpr (methods::CompleteTaskPayloadHas::getClientMutationIdWithParams) + { + return { _pimpl->getClientMutationId(std::move(params)) }; + } + else if constexpr (methods::CompleteTaskPayloadHas::getClientMutationId) + { + return { _pimpl->getClientMutationId() }; + } + else + { + throw std::runtime_error(R"ex(CompleteTaskPayload::getClientMutationId is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::CompleteTaskPayloadHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::CompleteTaskPayloadHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + CompleteTaskPayload(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + CompleteTaskPayload(std::shared_ptr pimpl) noexcept + : CompleteTaskPayload { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // COMPLETETASKPAYLOADOBJECT_H diff --git a/samples/today/nointrospection/ExpensiveObject.cpp b/samples/today/nointrospection/ExpensiveObject.cpp new file mode 100644 index 00000000..55268ab3 --- /dev/null +++ b/samples/today/nointrospection/ExpensiveObject.cpp @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "ExpensiveObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Expensive::Expensive(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Expensive::getTypeNames() const noexcept +{ + return { + R"gql(Expensive)gql"sv + }; +} + +service::ResolverMap Expensive::getResolvers() const noexcept +{ + return { + { R"gql(order)gql"sv, [this](service::ResolverParams&& params) { return resolveOrder(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void Expensive::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Expensive::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Expensive::resolveOrder(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getOrder(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Expensive::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Expensive)gql" }, std::move(params)); +} + +} // namespace object + +void AddExpensiveDetails(const std::shared_ptr& typeExpensive, const std::shared_ptr& schema) +{ + typeExpensive->AddFields({ + schema::Field::Make(R"gql(order)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/ExpensiveObject.h b/samples/today/nointrospection/ExpensiveObject.h new file mode 100644 index 00000000..19c717e1 --- /dev/null +++ b/samples/today/nointrospection/ExpensiveObject.h @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef EXPENSIVEOBJECT_H +#define EXPENSIVEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::ExpensiveHas { + +template +concept getOrderWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getOrder(std::move(params)) } }; +}; + +template +concept getOrder = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getOrder() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::ExpensiveHas + +class Expensive + : public service::Object +{ +private: + service::AwaitableResolver resolveOrder(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getOrder(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getOrder(service::FieldParams&& params) const final + { + if constexpr (methods::ExpensiveHas::getOrderWithParams) + { + return { _pimpl->getOrder(std::move(params)) }; + } + else if constexpr (methods::ExpensiveHas::getOrder) + { + return { _pimpl->getOrder() }; + } + else + { + throw std::runtime_error(R"ex(Expensive::getOrder is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::ExpensiveHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::ExpensiveHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Expensive(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Expensive(std::shared_ptr pimpl) noexcept + : Expensive { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // EXPENSIVEOBJECT_H diff --git a/samples/today/nointrospection/FolderConnectionObject.cpp b/samples/today/nointrospection/FolderConnectionObject.cpp new file mode 100644 index 00000000..8008268e --- /dev/null +++ b/samples/today/nointrospection/FolderConnectionObject.cpp @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "FolderConnectionObject.h" +#include "PageInfoObject.h" +#include "FolderEdgeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +FolderConnection::FolderConnection(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames FolderConnection::getTypeNames() const noexcept +{ + return { + R"gql(FolderConnection)gql"sv + }; +} + +service::ResolverMap FolderConnection::getResolvers() const noexcept +{ + return { + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void FolderConnection::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void FolderConnection::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver FolderConnection::resolvePageInfo(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver FolderConnection::resolveEdges(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver FolderConnection::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(FolderConnection)gql" }, std::move(params)); +} + +} // namespace object + +void AddFolderConnectionDetails(const std::shared_ptr& typeFolderConnection, const std::shared_ptr& schema) +{ + typeFolderConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PageInfo)gql"sv))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(FolderEdge)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/FolderConnectionObject.h b/samples/today/nointrospection/FolderConnectionObject.h new file mode 100644 index 00000000..cd92557b --- /dev/null +++ b/samples/today/nointrospection/FolderConnectionObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef FOLDERCONNECTIONOBJECT_H +#define FOLDERCONNECTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::FolderConnectionHas { + +template +concept getPageInfoWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getPageInfo(std::move(params)) } }; +}; + +template +concept getPageInfo = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getPageInfo() } }; +}; + +template +concept getEdgesWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject>>> { impl.getEdges(std::move(params)) } }; +}; + +template +concept getEdges = requires (TImpl impl) +{ + { service::AwaitableObject>>> { impl.getEdges() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::FolderConnectionHas + +class FolderConnection + : public service::Object +{ +private: + service::AwaitableResolver resolvePageInfo(service::ResolverParams&& params) const; + service::AwaitableResolver resolveEdges(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getPageInfo(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>>> getEdges(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getPageInfo(service::FieldParams&& params) const final + { + if constexpr (methods::FolderConnectionHas::getPageInfoWithParams) + { + return { _pimpl->getPageInfo(std::move(params)) }; + } + else if constexpr (methods::FolderConnectionHas::getPageInfo) + { + return { _pimpl->getPageInfo() }; + } + else + { + throw std::runtime_error(R"ex(FolderConnection::getPageInfo is not implemented)ex"); + } + } + + service::AwaitableObject>>> getEdges(service::FieldParams&& params) const final + { + if constexpr (methods::FolderConnectionHas::getEdgesWithParams) + { + return { _pimpl->getEdges(std::move(params)) }; + } + else if constexpr (methods::FolderConnectionHas::getEdges) + { + return { _pimpl->getEdges() }; + } + else + { + throw std::runtime_error(R"ex(FolderConnection::getEdges is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderConnectionHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderConnectionHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + FolderConnection(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + FolderConnection(std::shared_ptr pimpl) noexcept + : FolderConnection { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // FOLDERCONNECTIONOBJECT_H diff --git a/samples/today/nointrospection/FolderEdgeObject.cpp b/samples/today/nointrospection/FolderEdgeObject.cpp new file mode 100644 index 00000000..b26cb3b0 --- /dev/null +++ b/samples/today/nointrospection/FolderEdgeObject.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "FolderEdgeObject.h" +#include "FolderObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +FolderEdge::FolderEdge(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames FolderEdge::getTypeNames() const noexcept +{ + return { + R"gql(FolderEdge)gql"sv + }; +} + +service::ResolverMap FolderEdge::getResolvers() const noexcept +{ + return { + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void FolderEdge::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void FolderEdge::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver FolderEdge::resolveNode(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver FolderEdge::resolveCursor(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver FolderEdge::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(FolderEdge)gql" }, std::move(params)); +} + +} // namespace object + +void AddFolderEdgeDetails(const std::shared_ptr& typeFolderEdge, const std::shared_ptr& schema) +{ + typeFolderEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Folder)gql"sv)), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ItemCursor)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/FolderEdgeObject.h b/samples/today/nointrospection/FolderEdgeObject.h new file mode 100644 index 00000000..65280232 --- /dev/null +++ b/samples/today/nointrospection/FolderEdgeObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef FOLDEREDGEOBJECT_H +#define FOLDEREDGEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::FolderEdgeHas { + +template +concept getNodeWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNode(std::move(params)) } }; +}; + +template +concept getNode = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNode() } }; +}; + +template +concept getCursorWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getCursor(std::move(params)) } }; +}; + +template +concept getCursor = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getCursor() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::FolderEdgeHas + +class FolderEdge + : public service::Object +{ +private: + service::AwaitableResolver resolveNode(service::ResolverParams&& params) const; + service::AwaitableResolver resolveCursor(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getNode(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getCursor(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getNode(service::FieldParams&& params) const final + { + if constexpr (methods::FolderEdgeHas::getNodeWithParams) + { + return { _pimpl->getNode(std::move(params)) }; + } + else if constexpr (methods::FolderEdgeHas::getNode) + { + return { _pimpl->getNode() }; + } + else + { + throw std::runtime_error(R"ex(FolderEdge::getNode is not implemented)ex"); + } + } + + service::AwaitableScalar getCursor(service::FieldParams&& params) const final + { + if constexpr (methods::FolderEdgeHas::getCursorWithParams) + { + return { _pimpl->getCursor(std::move(params)) }; + } + else if constexpr (methods::FolderEdgeHas::getCursor) + { + return { _pimpl->getCursor() }; + } + else + { + throw std::runtime_error(R"ex(FolderEdge::getCursor is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderEdgeHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderEdgeHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + FolderEdge(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + FolderEdge(std::shared_ptr pimpl) noexcept + : FolderEdge { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // FOLDEREDGEOBJECT_H diff --git a/samples/today/nointrospection/FolderObject.cpp b/samples/today/nointrospection/FolderObject.cpp new file mode 100644 index 00000000..700f5414 --- /dev/null +++ b/samples/today/nointrospection/FolderObject.cpp @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "FolderObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Folder::Folder(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Folder::getTypeNames() const noexcept +{ + return { + R"gql(Node)gql"sv, + R"gql(UnionType)gql"sv, + R"gql(Folder)gql"sv + }; +} + +service::ResolverMap Folder::getResolvers() const noexcept +{ + return { + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(unreadCount)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCount(std::move(params)); } } + }; +} + +void Folder::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Folder::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Folder::resolveId(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Folder::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Folder::resolveUnreadCount(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getUnreadCount(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Folder::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Folder)gql" }, std::move(params)); +} + +} // namespace object + +void AddFolderDetails(const std::shared_ptr& typeFolder, const std::shared_ptr& schema) +{ + typeFolder->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) + }); + typeFolder->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))), + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(unreadCount)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/FolderObject.h b/samples/today/nointrospection/FolderObject.h new file mode 100644 index 00000000..9d2cbbfc --- /dev/null +++ b/samples/today/nointrospection/FolderObject.h @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef FOLDEROBJECT_H +#define FOLDEROBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace implements { + +template +concept FolderIs = std::is_same_v || std::is_same_v; + +} // namespace implements + +namespace methods::FolderHas { + +template +concept getIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getId(std::move(params)) } }; +}; + +template +concept getId = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getId() } }; +}; + +template +concept getNameWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getName(std::move(params)) } }; +}; + +template +concept getName = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getName() } }; +}; + +template +concept getUnreadCountWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getUnreadCount(std::move(params)) } }; +}; + +template +concept getUnreadCount = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getUnreadCount() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::FolderHas + +class Folder + : public service::Object +{ +private: + service::AwaitableResolver resolveId(service::ResolverParams&& params) const; + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveUnreadCount(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getId(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getName(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getUnreadCount(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getId(service::FieldParams&& params) const final + { + if constexpr (methods::FolderHas::getIdWithParams) + { + return { _pimpl->getId(std::move(params)) }; + } + else if constexpr (methods::FolderHas::getId) + { + return { _pimpl->getId() }; + } + else + { + throw std::runtime_error(R"ex(Folder::getId is not implemented)ex"); + } + } + + service::AwaitableScalar> getName(service::FieldParams&& params) const final + { + if constexpr (methods::FolderHas::getNameWithParams) + { + return { _pimpl->getName(std::move(params)) }; + } + else if constexpr (methods::FolderHas::getName) + { + return { _pimpl->getName() }; + } + else + { + throw std::runtime_error(R"ex(Folder::getName is not implemented)ex"); + } + } + + service::AwaitableScalar getUnreadCount(service::FieldParams&& params) const final + { + if constexpr (methods::FolderHas::getUnreadCountWithParams) + { + return { _pimpl->getUnreadCount(std::move(params)) }; + } + else if constexpr (methods::FolderHas::getUnreadCount) + { + return { _pimpl->getUnreadCount() }; + } + else + { + throw std::runtime_error(R"ex(Folder::getUnreadCount is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Folder(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Node; + + // Unions which include this type + friend UnionType; + + template + static constexpr bool implements() noexcept + { + return implements::FolderIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Folder(std::shared_ptr pimpl) noexcept + : Folder { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // FOLDEROBJECT_H diff --git a/samples/today/nointrospection/MutationObject.cpp b/samples/today/nointrospection/MutationObject.cpp new file mode 100644 index 00000000..97241a03 --- /dev/null +++ b/samples/today/nointrospection/MutationObject.cpp @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "MutationObject.h" +#include "CompleteTaskPayloadObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Mutation::Mutation(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Mutation::getTypeNames() const noexcept +{ + return { + R"gql(Mutation)gql"sv + }; +} + +service::ResolverMap Mutation::getResolvers() const noexcept +{ + return { + { R"gql(setFloat)gql"sv, [this](service::ResolverParams&& params) { return resolveSetFloat(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(completeTask)gql"sv, [this](service::ResolverParams&& params) { return resolveCompleteTask(std::move(params)); } } + }; +} + +void Mutation::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Mutation::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Mutation::resolveCompleteTask(service::ResolverParams&& params) const +{ + auto argInput = service::ModifiedArgument::require("input", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->applyCompleteTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argInput)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Mutation::resolveSetFloat(service::ResolverParams&& params) const +{ + auto argValue = service::ModifiedArgument::require("value", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->applySetFloat(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argValue)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Mutation::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Mutation)gql" }, std::move(params)); +} + +} // namespace object + +void AddMutationDetails(const std::shared_ptr& typeMutation, const std::shared_ptr& schema) +{ + typeMutation->AddFields({ + schema::Field::Make(R"gql(completeTask)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(CompleteTaskPayload)gql"sv)), { + schema::InputValue::Make(R"gql(input)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(CompleteTaskInput)gql"sv)), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(setFloat)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Float)gql"sv)), { + schema::InputValue::Make(R"gql(value)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Float)gql"sv)), R"gql()gql"sv) + }) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/MutationObject.h b/samples/today/nointrospection/MutationObject.h new file mode 100644 index 00000000..8ef746d8 --- /dev/null +++ b/samples/today/nointrospection/MutationObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef MUTATIONOBJECT_H +#define MUTATIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::MutationHas { + +template +concept applyCompleteTaskWithParams = requires (TImpl impl, service::FieldParams params, CompleteTaskInput inputArg) +{ + { service::AwaitableObject> { impl.applyCompleteTask(std::move(params), std::move(inputArg)) } }; +}; + +template +concept applyCompleteTask = requires (TImpl impl, CompleteTaskInput inputArg) +{ + { service::AwaitableObject> { impl.applyCompleteTask(std::move(inputArg)) } }; +}; + +template +concept applySetFloatWithParams = requires (TImpl impl, service::FieldParams params, double valueArg) +{ + { service::AwaitableScalar { impl.applySetFloat(std::move(params), std::move(valueArg)) } }; +}; + +template +concept applySetFloat = requires (TImpl impl, double valueArg) +{ + { service::AwaitableScalar { impl.applySetFloat(std::move(valueArg)) } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::MutationHas + +class Mutation + : public service::Object +{ +private: + service::AwaitableResolver resolveCompleteTask(service::ResolverParams&& params) const; + service::AwaitableResolver resolveSetFloat(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> applyCompleteTask(service::FieldParams&& params, CompleteTaskInput&& inputArg) const = 0; + virtual service::AwaitableScalar applySetFloat(service::FieldParams&& params, double&& valueArg) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> applyCompleteTask(service::FieldParams&& params, CompleteTaskInput&& inputArg) const final + { + if constexpr (methods::MutationHas::applyCompleteTaskWithParams) + { + return { _pimpl->applyCompleteTask(std::move(params), std::move(inputArg)) }; + } + else if constexpr (methods::MutationHas::applyCompleteTask) + { + return { _pimpl->applyCompleteTask(std::move(inputArg)) }; + } + else + { + throw std::runtime_error(R"ex(Mutation::applyCompleteTask is not implemented)ex"); + } + } + + service::AwaitableScalar applySetFloat(service::FieldParams&& params, double&& valueArg) const final + { + if constexpr (methods::MutationHas::applySetFloatWithParams) + { + return { _pimpl->applySetFloat(std::move(params), std::move(valueArg)) }; + } + else if constexpr (methods::MutationHas::applySetFloat) + { + return { _pimpl->applySetFloat(std::move(valueArg)) }; + } + else + { + throw std::runtime_error(R"ex(Mutation::applySetFloat is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MutationHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MutationHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Mutation(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Mutation(std::shared_ptr pimpl) noexcept + : Mutation { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // MUTATIONOBJECT_H diff --git a/samples/today/nointrospection/NestedTypeObject.cpp b/samples/today/nointrospection/NestedTypeObject.cpp new file mode 100644 index 00000000..1bb57acd --- /dev/null +++ b/samples/today/nointrospection/NestedTypeObject.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "NestedTypeObject.h" +#include "NestedTypeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +NestedType::NestedType(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames NestedType::getTypeNames() const noexcept +{ + return { + R"gql(NestedType)gql"sv + }; +} + +service::ResolverMap NestedType::getResolvers() const noexcept +{ + return { + { R"gql(depth)gql"sv, [this](service::ResolverParams&& params) { return resolveDepth(std::move(params)); } }, + { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void NestedType::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void NestedType::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver NestedType::resolveDepth(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getDepth(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver NestedType::resolveNested(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver NestedType::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(NestedType)gql" }, std::move(params)); +} + +} // namespace object + +void AddNestedTypeDetails(const std::shared_ptr& typeNestedType, const std::shared_ptr& schema) +{ + typeNestedType->AddFields({ + schema::Field::Make(R"gql(depth)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv))), + schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(NestedType)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/NestedTypeObject.h b/samples/today/nointrospection/NestedTypeObject.h new file mode 100644 index 00000000..a2f0e22f --- /dev/null +++ b/samples/today/nointrospection/NestedTypeObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef NESTEDTYPEOBJECT_H +#define NESTEDTYPEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::NestedTypeHas { + +template +concept getDepthWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getDepth(std::move(params)) } }; +}; + +template +concept getDepth = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getDepth() } }; +}; + +template +concept getNestedWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNested(std::move(params)) } }; +}; + +template +concept getNested = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNested() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::NestedTypeHas + +class NestedType + : public service::Object +{ +private: + service::AwaitableResolver resolveDepth(service::ResolverParams&& params) const; + service::AwaitableResolver resolveNested(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getDepth(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject> getNested(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getDepth(service::FieldParams&& params) const final + { + if constexpr (methods::NestedTypeHas::getDepthWithParams) + { + return { _pimpl->getDepth(std::move(params)) }; + } + else if constexpr (methods::NestedTypeHas::getDepth) + { + return { _pimpl->getDepth() }; + } + else + { + throw std::runtime_error(R"ex(NestedType::getDepth is not implemented)ex"); + } + } + + service::AwaitableObject> getNested(service::FieldParams&& params) const final + { + if constexpr (methods::NestedTypeHas::getNestedWithParams) + { + return { _pimpl->getNested(std::move(params)) }; + } + else if constexpr (methods::NestedTypeHas::getNested) + { + return { _pimpl->getNested() }; + } + else + { + throw std::runtime_error(R"ex(NestedType::getNested is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::NestedTypeHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::NestedTypeHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + NestedType(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + NestedType(std::shared_ptr pimpl) noexcept + : NestedType { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // NESTEDTYPEOBJECT_H diff --git a/samples/today/nointrospection/NodeObject.cpp b/samples/today/nointrospection/NodeObject.cpp new file mode 100644 index 00000000..93d80e05 --- /dev/null +++ b/samples/today/nointrospection/NodeObject.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "NodeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Node::Node(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void Node::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Node::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddNodeDetails(const std::shared_ptr& typeNode, const std::shared_ptr& schema) +{ + typeNode->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/NodeObject.h b/samples/today/nointrospection/NodeObject.h new file mode 100644 index 00000000..af1a537b --- /dev/null +++ b/samples/today/nointrospection/NodeObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef NODEOBJECT_H +#define NODEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class Node + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + Node(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Node(std::shared_ptr pimpl) noexcept + : Node { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "Node is not implemented"); + } +}; + +} // namespace graphql::today::object + +#endif // NODEOBJECT_H diff --git a/samples/today/nointrospection/PageInfoObject.cpp b/samples/today/nointrospection/PageInfoObject.cpp new file mode 100644 index 00000000..b271ead9 --- /dev/null +++ b/samples/today/nointrospection/PageInfoObject.cpp @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "PageInfoObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +PageInfo::PageInfo(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames PageInfo::getTypeNames() const noexcept +{ + return { + R"gql(PageInfo)gql"sv + }; +} + +service::ResolverMap PageInfo::getResolvers() const noexcept +{ + return { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(hasNextPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasNextPage(std::move(params)); } }, + { R"gql(hasPreviousPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasPreviousPage(std::move(params)); } } + }; +} + +void PageInfo::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void PageInfo::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver PageInfo::resolveHasNextPage(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getHasNextPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getHasPreviousPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver PageInfo::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(PageInfo)gql" }, std::move(params)); +} + +} // namespace object + +void AddPageInfoDetails(const std::shared_ptr& typePageInfo, const std::shared_ptr& schema) +{ + typePageInfo->AddFields({ + schema::Field::Make(R"gql(hasNextPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))), + schema::Field::Make(R"gql(hasPreviousPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/PageInfoObject.h b/samples/today/nointrospection/PageInfoObject.h new file mode 100644 index 00000000..5c46a6c6 --- /dev/null +++ b/samples/today/nointrospection/PageInfoObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef PAGEINFOOBJECT_H +#define PAGEINFOOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::PageInfoHas { + +template +concept getHasNextPageWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getHasNextPage(std::move(params)) } }; +}; + +template +concept getHasNextPage = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getHasNextPage() } }; +}; + +template +concept getHasPreviousPageWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getHasPreviousPage(std::move(params)) } }; +}; + +template +concept getHasPreviousPage = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getHasPreviousPage() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::PageInfoHas + +class PageInfo + : public service::Object +{ +private: + service::AwaitableResolver resolveHasNextPage(service::ResolverParams&& params) const; + service::AwaitableResolver resolveHasPreviousPage(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getHasNextPage(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getHasPreviousPage(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getHasNextPage(service::FieldParams&& params) const final + { + if constexpr (methods::PageInfoHas::getHasNextPageWithParams) + { + return { _pimpl->getHasNextPage(std::move(params)) }; + } + else if constexpr (methods::PageInfoHas::getHasNextPage) + { + return { _pimpl->getHasNextPage() }; + } + else + { + throw std::runtime_error(R"ex(PageInfo::getHasNextPage is not implemented)ex"); + } + } + + service::AwaitableScalar getHasPreviousPage(service::FieldParams&& params) const final + { + if constexpr (methods::PageInfoHas::getHasPreviousPageWithParams) + { + return { _pimpl->getHasPreviousPage(std::move(params)) }; + } + else if constexpr (methods::PageInfoHas::getHasPreviousPage) + { + return { _pimpl->getHasPreviousPage() }; + } + else + { + throw std::runtime_error(R"ex(PageInfo::getHasPreviousPage is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::PageInfoHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::PageInfoHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + PageInfo(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + PageInfo(std::shared_ptr pimpl) noexcept + : PageInfo { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // PAGEINFOOBJECT_H diff --git a/samples/separate_nointrospection/QueryObject.cpp b/samples/today/nointrospection/QueryObject.cpp similarity index 54% rename from samples/separate_nointrospection/QueryObject.cpp rename to samples/today/nointrospection/QueryObject.cpp index b4c19b3b..0fda8961 100644 --- a/samples/separate_nointrospection/QueryObject.cpp +++ b/samples/today/nointrospection/QueryObject.cpp @@ -3,9 +3,21 @@ // WARNING! Do not edit this file manually, your changes will be overwritten. -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" +#include "QueryObject.h" +#include "NodeObject.h" +#include "AppointmentConnectionObject.h" +#include "TaskConnectionObject.h" +#include "FolderConnectionObject.h" +#include "AppointmentObject.h" +#include "TaskObject.h" +#include "FolderObject.h" +#include "NestedTypeObject.h" +#include "ExpensiveObject.h" +#include "UnionTypeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" #include #include @@ -18,10 +30,22 @@ using namespace std::literals; namespace graphql::today { namespace object { -Query::Query() - : service::Object({ - "Query" - }, { +Query::Query(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Query::getTypeNames() const noexcept +{ + return { + R"gql(Query)gql"sv + }; +} + +service::ResolverMap Query::getResolvers() const noexcept +{ + return { { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, { R"gql(tasks)gql"sv, [this](service::ResolverParams&& params) { return resolveTasks(std::move(params)); } }, { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } }, @@ -35,91 +59,75 @@ Query::Query() { R"gql(unimplemented)gql"sv, [this](service::ResolverParams&& params) { return resolveUnimplemented(std::move(params)); } }, { R"gql(appointmentsById)gql"sv, [this](service::ResolverParams&& params) { return resolveAppointmentsById(std::move(params)); } }, { R"gql(unreadCountsById)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCountsById(std::move(params)); } } - }) + }; +} + +void Query::beginSelectionSet(const service::SelectionSetParams& params) const { + _pimpl->beginSelectionSet(params); } -service::FieldResult> Query::getNode(service::FieldParams&&, response::IdType&&) const +void Query::endSelectionSet(const service::SelectionSetParams& params) const { - throw std::runtime_error(R"ex(Query::getNode is not implemented)ex"); + _pimpl->endSelectionSet(params); } -std::future Query::resolveNode(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveNode(service::ResolverParams&& params) const { auto argId = service::ModifiedArgument::require("id", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); + auto result = _pimpl->getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); resolverLock.unlock(); - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getAppointments(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getAppointments is not implemented)ex"); + return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Query::resolveAppointments(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveAppointments(service::ResolverParams&& params) const { - auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); auto argBefore = service::ModifiedArgument::require("before", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getAppointments(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + auto result = _pimpl->getAppointments(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult> Query::getTasks(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getTasks is not implemented)ex"); -} - -std::future Query::resolveTasks(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveTasks(service::ResolverParams&& params) const { - auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); auto argBefore = service::ModifiedArgument::require("before", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getTasks(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + auto result = _pimpl->getTasks(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult> Query::getUnreadCounts(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const +service::AwaitableResolver Query::resolveUnreadCounts(service::ResolverParams&& params) const { - throw std::runtime_error(R"ex(Query::getUnreadCounts is not implemented)ex"); -} - -std::future Query::resolveUnreadCounts(service::ResolverParams&& params) -{ - auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); auto argBefore = service::ModifiedArgument::require("before", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCounts(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + auto result = _pimpl->getUnreadCounts(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult>> Query::getAppointmentsById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getAppointmentsById is not implemented)ex"); -} - -std::future Query::resolveAppointmentsById(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveAppointmentsById(service::ResolverParams&& params) const { - const auto defaultArguments = []() + static const auto defaultArguments = []() { response::Value values(response::Type::Map); response::Value entry; @@ -144,166 +152,131 @@ std::future Query::resolveAppointmentsById(service::Res : service::ModifiedArgument::require("ids", defaultArguments)); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getAppointmentsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); + auto result = _pimpl->getAppointmentsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult>> Query::getTasksById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getTasksById is not implemented)ex"); -} - -std::future Query::resolveTasksById(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveTasksById(service::ResolverParams&& params) const { auto argIds = service::ModifiedArgument::require("ids", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getTasksById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); + auto result = _pimpl->getTasksById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult>> Query::getUnreadCountsById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getUnreadCountsById is not implemented)ex"); -} - -std::future Query::resolveUnreadCountsById(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveUnreadCountsById(service::ResolverParams&& params) const { auto argIds = service::ModifiedArgument::require("ids", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCountsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); + auto result = _pimpl->getUnreadCountsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult> Query::getNested(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getNested is not implemented)ex"); -} - -std::future Query::resolveNested(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveNested(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult Query::getUnimplemented(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getUnimplemented is not implemented)ex"); -} - -std::future Query::resolveUnimplemented(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveUnimplemented(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getUnimplemented(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getUnimplemented(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); - return service::ModifiedResult::convert(std::move(result), std::move(params)); + return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult>> Query::getExpensive(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getExpensive is not implemented)ex"); -} - -std::future Query::resolveExpensive(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveExpensive(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getExpensive(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getExpensive(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult Query::getTestTaskState(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getTestTaskState is not implemented)ex"); -} - -std::future Query::resolveTestTaskState(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveTestTaskState(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getTestTaskState(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getTestTaskState(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult>> Query::getAnyType(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getAnyType is not implemented)ex"); -} - -std::future Query::resolveAnyType(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveAnyType(service::ResolverParams&& params) const { auto argIds = service::ModifiedArgument::require("ids", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getAnyType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); + auto result = _pimpl->getAnyType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); resolverLock.unlock(); - return service::ModifiedResult::convert(std::move(result), std::move(params)); + return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Query::resolve_typename(service::ResolverParams&& params) +service::AwaitableResolver Query::resolve_typename(service::ResolverParams&& params) const { - return service::ModifiedResult::convert(response::StringType{ R"gql(Query)gql" }, std::move(params)); + return service::ModifiedResult::convert(std::string{ R"gql(Query)gql" }, std::move(params)); } } // namespace object -void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema) +void AddQueryDetails(const std::shared_ptr& typeQuery, const std::shared_ptr& schema) { typeQuery->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Node"), { - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Node)gql"sv), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv) }), - schema::Field::Make(R"gql(appointments)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("AppointmentConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + schema::Field::Make(R"gql(appointments)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(AppointmentConnection)gql"sv)), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv) }), - schema::Field::Make(R"gql(tasks)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + schema::Field::Make(R"gql(tasks)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(TaskConnection)gql"sv)), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv) }), - schema::Field::Make(R"gql(unreadCounts)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("FolderConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + schema::Field::Make(R"gql(unreadCounts)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(FolderConnection)gql"sv)), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv) }), - schema::Field::Make(R"gql(appointmentsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Appointment"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql"sv) + schema::Field::Make(R"gql(appointmentsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Appointment)gql"sv))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql"sv) }), - schema::Field::Make(R"gql(tasksById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Task"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + schema::Field::Make(R"gql(tasksById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Task)gql"sv))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)))), R"gql()gql"sv) }), - schema::Field::Make(R"gql(unreadCountsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Folder"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + schema::Field::Make(R"gql(unreadCountsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Folder)gql"sv))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)))), R"gql()gql"sv) }), - schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))), - schema::Field::Make(R"gql(unimplemented)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(expensive)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Expensive"))))), - schema::Field::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskState"))), - schema::Field::Make(R"gql(anyType)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("UnionType"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(NestedType)gql"sv))), + schema::Field::Make(R"gql(unimplemented)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(expensive)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Expensive)gql"sv))))), + schema::Field::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(TaskState)gql"sv))), + schema::Field::Make(R"gql(anyType)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(UnionType)gql"sv))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)))), R"gql()gql"sv) }) }); } diff --git a/samples/today/nointrospection/QueryObject.h b/samples/today/nointrospection/QueryObject.h new file mode 100644 index 00000000..d4485e1a --- /dev/null +++ b/samples/today/nointrospection/QueryObject.h @@ -0,0 +1,455 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef QUERYOBJECT_H +#define QUERYOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::QueryHas { + +template +concept getNodeWithParams = requires (TImpl impl, service::FieldParams params, response::IdType idArg) +{ + { service::AwaitableObject> { impl.getNode(std::move(params), std::move(idArg)) } }; +}; + +template +concept getNode = requires (TImpl impl, response::IdType idArg) +{ + { service::AwaitableObject> { impl.getNode(std::move(idArg)) } }; +}; + +template +concept getAppointmentsWithParams = requires (TImpl impl, service::FieldParams params, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getAppointments(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getAppointments = requires (TImpl impl, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getAppointments(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getTasksWithParams = requires (TImpl impl, service::FieldParams params, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getTasks(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getTasks = requires (TImpl impl, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getTasks(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getUnreadCountsWithParams = requires (TImpl impl, service::FieldParams params, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getUnreadCounts(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getUnreadCounts = requires (TImpl impl, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getUnreadCounts(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getAppointmentsByIdWithParams = requires (TImpl impl, service::FieldParams params, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getAppointmentsById(std::move(params), std::move(idsArg)) } }; +}; + +template +concept getAppointmentsById = requires (TImpl impl, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getAppointmentsById(std::move(idsArg)) } }; +}; + +template +concept getTasksByIdWithParams = requires (TImpl impl, service::FieldParams params, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getTasksById(std::move(params), std::move(idsArg)) } }; +}; + +template +concept getTasksById = requires (TImpl impl, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getTasksById(std::move(idsArg)) } }; +}; + +template +concept getUnreadCountsByIdWithParams = requires (TImpl impl, service::FieldParams params, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getUnreadCountsById(std::move(params), std::move(idsArg)) } }; +}; + +template +concept getUnreadCountsById = requires (TImpl impl, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getUnreadCountsById(std::move(idsArg)) } }; +}; + +template +concept getNestedWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNested(std::move(params)) } }; +}; + +template +concept getNested = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNested() } }; +}; + +template +concept getUnimplementedWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getUnimplemented(std::move(params)) } }; +}; + +template +concept getUnimplemented = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getUnimplemented() } }; +}; + +template +concept getExpensiveWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject>> { impl.getExpensive(std::move(params)) } }; +}; + +template +concept getExpensive = requires (TImpl impl) +{ + { service::AwaitableObject>> { impl.getExpensive() } }; +}; + +template +concept getTestTaskStateWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getTestTaskState(std::move(params)) } }; +}; + +template +concept getTestTaskState = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getTestTaskState() } }; +}; + +template +concept getAnyTypeWithParams = requires (TImpl impl, service::FieldParams params, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getAnyType(std::move(params), std::move(idsArg)) } }; +}; + +template +concept getAnyType = requires (TImpl impl, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getAnyType(std::move(idsArg)) } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::QueryHas + +class Query + : public service::Object +{ +private: + service::AwaitableResolver resolveNode(service::ResolverParams&& params) const; + service::AwaitableResolver resolveAppointments(service::ResolverParams&& params) const; + service::AwaitableResolver resolveTasks(service::ResolverParams&& params) const; + service::AwaitableResolver resolveUnreadCounts(service::ResolverParams&& params) const; + service::AwaitableResolver resolveAppointmentsById(service::ResolverParams&& params) const; + service::AwaitableResolver resolveTasksById(service::ResolverParams&& params) const; + service::AwaitableResolver resolveUnreadCountsById(service::ResolverParams&& params) const; + service::AwaitableResolver resolveNested(service::ResolverParams&& params) const; + service::AwaitableResolver resolveUnimplemented(service::ResolverParams&& params) const; + service::AwaitableResolver resolveExpensive(service::ResolverParams&& params) const; + service::AwaitableResolver resolveTestTaskState(service::ResolverParams&& params) const; + service::AwaitableResolver resolveAnyType(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getNode(service::FieldParams&& params, response::IdType&& idArg) const = 0; + virtual service::AwaitableObject> getAppointments(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const = 0; + virtual service::AwaitableObject> getTasks(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const = 0; + virtual service::AwaitableObject> getUnreadCounts(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const = 0; + virtual service::AwaitableObject>> getAppointmentsById(service::FieldParams&& params, std::vector&& idsArg) const = 0; + virtual service::AwaitableObject>> getTasksById(service::FieldParams&& params, std::vector&& idsArg) const = 0; + virtual service::AwaitableObject>> getUnreadCountsById(service::FieldParams&& params, std::vector&& idsArg) const = 0; + virtual service::AwaitableObject> getNested(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getUnimplemented(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>> getExpensive(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getTestTaskState(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>> getAnyType(service::FieldParams&& params, std::vector&& idsArg) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getNode(service::FieldParams&& params, response::IdType&& idArg) const final + { + if constexpr (methods::QueryHas::getNodeWithParams) + { + return { _pimpl->getNode(std::move(params), std::move(idArg)) }; + } + else if constexpr (methods::QueryHas::getNode) + { + return { _pimpl->getNode(std::move(idArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getNode is not implemented)ex"); + } + } + + service::AwaitableObject> getAppointments(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const final + { + if constexpr (methods::QueryHas::getAppointmentsWithParams) + { + return { _pimpl->getAppointments(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else if constexpr (methods::QueryHas::getAppointments) + { + return { _pimpl->getAppointments(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getAppointments is not implemented)ex"); + } + } + + service::AwaitableObject> getTasks(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const final + { + if constexpr (methods::QueryHas::getTasksWithParams) + { + return { _pimpl->getTasks(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else if constexpr (methods::QueryHas::getTasks) + { + return { _pimpl->getTasks(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getTasks is not implemented)ex"); + } + } + + service::AwaitableObject> getUnreadCounts(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const final + { + if constexpr (methods::QueryHas::getUnreadCountsWithParams) + { + return { _pimpl->getUnreadCounts(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else if constexpr (methods::QueryHas::getUnreadCounts) + { + return { _pimpl->getUnreadCounts(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getUnreadCounts is not implemented)ex"); + } + } + + service::AwaitableObject>> getAppointmentsById(service::FieldParams&& params, std::vector&& idsArg) const final + { + if constexpr (methods::QueryHas::getAppointmentsByIdWithParams) + { + return { _pimpl->getAppointmentsById(std::move(params), std::move(idsArg)) }; + } + else if constexpr (methods::QueryHas::getAppointmentsById) + { + return { _pimpl->getAppointmentsById(std::move(idsArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getAppointmentsById is not implemented)ex"); + } + } + + service::AwaitableObject>> getTasksById(service::FieldParams&& params, std::vector&& idsArg) const final + { + if constexpr (methods::QueryHas::getTasksByIdWithParams) + { + return { _pimpl->getTasksById(std::move(params), std::move(idsArg)) }; + } + else if constexpr (methods::QueryHas::getTasksById) + { + return { _pimpl->getTasksById(std::move(idsArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getTasksById is not implemented)ex"); + } + } + + service::AwaitableObject>> getUnreadCountsById(service::FieldParams&& params, std::vector&& idsArg) const final + { + if constexpr (methods::QueryHas::getUnreadCountsByIdWithParams) + { + return { _pimpl->getUnreadCountsById(std::move(params), std::move(idsArg)) }; + } + else if constexpr (methods::QueryHas::getUnreadCountsById) + { + return { _pimpl->getUnreadCountsById(std::move(idsArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getUnreadCountsById is not implemented)ex"); + } + } + + service::AwaitableObject> getNested(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getNestedWithParams) + { + return { _pimpl->getNested(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getNested) + { + return { _pimpl->getNested() }; + } + else + { + throw std::runtime_error(R"ex(Query::getNested is not implemented)ex"); + } + } + + service::AwaitableScalar getUnimplemented(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getUnimplementedWithParams) + { + return { _pimpl->getUnimplemented(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getUnimplemented) + { + return { _pimpl->getUnimplemented() }; + } + else + { + throw std::runtime_error(R"ex(Query::getUnimplemented is not implemented)ex"); + } + } + + service::AwaitableObject>> getExpensive(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getExpensiveWithParams) + { + return { _pimpl->getExpensive(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getExpensive) + { + return { _pimpl->getExpensive() }; + } + else + { + throw std::runtime_error(R"ex(Query::getExpensive is not implemented)ex"); + } + } + + service::AwaitableScalar getTestTaskState(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getTestTaskStateWithParams) + { + return { _pimpl->getTestTaskState(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getTestTaskState) + { + return { _pimpl->getTestTaskState() }; + } + else + { + throw std::runtime_error(R"ex(Query::getTestTaskState is not implemented)ex"); + } + } + + service::AwaitableObject>> getAnyType(service::FieldParams&& params, std::vector&& idsArg) const final + { + if constexpr (methods::QueryHas::getAnyTypeWithParams) + { + return { _pimpl->getAnyType(std::move(params), std::move(idsArg)) }; + } + else if constexpr (methods::QueryHas::getAnyType) + { + return { _pimpl->getAnyType(std::move(idsArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getAnyType is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::QueryHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::QueryHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Query(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Query(std::shared_ptr pimpl) noexcept + : Query { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // QUERYOBJECT_H diff --git a/samples/today/nointrospection/SubscriptionObject.cpp b/samples/today/nointrospection/SubscriptionObject.cpp new file mode 100644 index 00000000..00d348ce --- /dev/null +++ b/samples/today/nointrospection/SubscriptionObject.cpp @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "SubscriptionObject.h" +#include "AppointmentObject.h" +#include "NodeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Subscription::Subscription(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Subscription::getTypeNames() const noexcept +{ + return { + R"gql(Subscription)gql"sv + }; +} + +service::ResolverMap Subscription::getResolvers() const noexcept +{ + return { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(nodeChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNodeChange(std::move(params)); } }, + { R"gql(nextAppointmentChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNextAppointmentChange(std::move(params)); } } + }; +} + +void Subscription::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Subscription::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNextAppointmentChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Subscription::resolveNodeChange(service::ResolverParams&& params) const +{ + auto argId = service::ModifiedArgument::require("id", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNodeChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Subscription::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Subscription)gql" }, std::move(params)); +} + +} // namespace object + +void AddSubscriptionDetails(const std::shared_ptr& typeSubscription, const std::shared_ptr& schema) +{ + typeSubscription->AddFields({ + schema::Field::Make(R"gql(nextAppointmentChange)gql"sv, R"md()md"sv, std::make_optional(R"md(Need to deprecate a [field](https://spec.graphql.org/October2021/#sec-Schema-Introspection.Deprecation))md"sv), schema->LookupType(R"gql(Appointment)gql"sv)), + schema::Field::Make(R"gql(nodeChange)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Node)gql"sv)), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv) + }) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/SubscriptionObject.h b/samples/today/nointrospection/SubscriptionObject.h new file mode 100644 index 00000000..4729e852 --- /dev/null +++ b/samples/today/nointrospection/SubscriptionObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef SUBSCRIPTIONOBJECT_H +#define SUBSCRIPTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::SubscriptionHas { + +template +concept getNextAppointmentChangeWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNextAppointmentChange(std::move(params)) } }; +}; + +template +concept getNextAppointmentChange = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNextAppointmentChange() } }; +}; + +template +concept getNodeChangeWithParams = requires (TImpl impl, service::FieldParams params, response::IdType idArg) +{ + { service::AwaitableObject> { impl.getNodeChange(std::move(params), std::move(idArg)) } }; +}; + +template +concept getNodeChange = requires (TImpl impl, response::IdType idArg) +{ + { service::AwaitableObject> { impl.getNodeChange(std::move(idArg)) } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::SubscriptionHas + +class Subscription + : public service::Object +{ +private: + service::AwaitableResolver resolveNextAppointmentChange(service::ResolverParams&& params) const; + service::AwaitableResolver resolveNodeChange(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getNextAppointmentChange(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getNextAppointmentChange(service::FieldParams&& params) const final + { + if constexpr (methods::SubscriptionHas::getNextAppointmentChangeWithParams) + { + return { _pimpl->getNextAppointmentChange(std::move(params)) }; + } + else if constexpr (methods::SubscriptionHas::getNextAppointmentChange) + { + return { _pimpl->getNextAppointmentChange() }; + } + else + { + throw std::runtime_error(R"ex(Subscription::getNextAppointmentChange is not implemented)ex"); + } + } + + service::AwaitableObject> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const final + { + if constexpr (methods::SubscriptionHas::getNodeChangeWithParams) + { + return { _pimpl->getNodeChange(std::move(params), std::move(idArg)) }; + } + else if constexpr (methods::SubscriptionHas::getNodeChange) + { + return { _pimpl->getNodeChange(std::move(idArg)) }; + } + else + { + throw std::runtime_error(R"ex(Subscription::getNodeChange is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::SubscriptionHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::SubscriptionHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Subscription(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Subscription(std::shared_ptr pimpl) noexcept + : Subscription { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // SUBSCRIPTIONOBJECT_H diff --git a/samples/today/nointrospection/TaskConnectionObject.cpp b/samples/today/nointrospection/TaskConnectionObject.cpp new file mode 100644 index 00000000..27c0c6b4 --- /dev/null +++ b/samples/today/nointrospection/TaskConnectionObject.cpp @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "TaskConnectionObject.h" +#include "PageInfoObject.h" +#include "TaskEdgeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +TaskConnection::TaskConnection(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames TaskConnection::getTypeNames() const noexcept +{ + return { + R"gql(TaskConnection)gql"sv + }; +} + +service::ResolverMap TaskConnection::getResolvers() const noexcept +{ + return { + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void TaskConnection::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void TaskConnection::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver TaskConnection::resolvePageInfo(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver TaskConnection::resolveEdges(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver TaskConnection::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(TaskConnection)gql" }, std::move(params)); +} + +} // namespace object + +void AddTaskConnectionDetails(const std::shared_ptr& typeTaskConnection, const std::shared_ptr& schema) +{ + typeTaskConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PageInfo)gql"sv))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(TaskEdge)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/TaskConnectionObject.h b/samples/today/nointrospection/TaskConnectionObject.h new file mode 100644 index 00000000..b926979d --- /dev/null +++ b/samples/today/nointrospection/TaskConnectionObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef TASKCONNECTIONOBJECT_H +#define TASKCONNECTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::TaskConnectionHas { + +template +concept getPageInfoWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getPageInfo(std::move(params)) } }; +}; + +template +concept getPageInfo = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getPageInfo() } }; +}; + +template +concept getEdgesWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject>>> { impl.getEdges(std::move(params)) } }; +}; + +template +concept getEdges = requires (TImpl impl) +{ + { service::AwaitableObject>>> { impl.getEdges() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::TaskConnectionHas + +class TaskConnection + : public service::Object +{ +private: + service::AwaitableResolver resolvePageInfo(service::ResolverParams&& params) const; + service::AwaitableResolver resolveEdges(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getPageInfo(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>>> getEdges(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getPageInfo(service::FieldParams&& params) const final + { + if constexpr (methods::TaskConnectionHas::getPageInfoWithParams) + { + return { _pimpl->getPageInfo(std::move(params)) }; + } + else if constexpr (methods::TaskConnectionHas::getPageInfo) + { + return { _pimpl->getPageInfo() }; + } + else + { + throw std::runtime_error(R"ex(TaskConnection::getPageInfo is not implemented)ex"); + } + } + + service::AwaitableObject>>> getEdges(service::FieldParams&& params) const final + { + if constexpr (methods::TaskConnectionHas::getEdgesWithParams) + { + return { _pimpl->getEdges(std::move(params)) }; + } + else if constexpr (methods::TaskConnectionHas::getEdges) + { + return { _pimpl->getEdges() }; + } + else + { + throw std::runtime_error(R"ex(TaskConnection::getEdges is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskConnectionHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskConnectionHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + TaskConnection(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + TaskConnection(std::shared_ptr pimpl) noexcept + : TaskConnection { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // TASKCONNECTIONOBJECT_H diff --git a/samples/today/nointrospection/TaskEdgeObject.cpp b/samples/today/nointrospection/TaskEdgeObject.cpp new file mode 100644 index 00000000..6780e548 --- /dev/null +++ b/samples/today/nointrospection/TaskEdgeObject.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "TaskEdgeObject.h" +#include "TaskObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +TaskEdge::TaskEdge(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames TaskEdge::getTypeNames() const noexcept +{ + return { + R"gql(TaskEdge)gql"sv + }; +} + +service::ResolverMap TaskEdge::getResolvers() const noexcept +{ + return { + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void TaskEdge::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void TaskEdge::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver TaskEdge::resolveNode(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver TaskEdge::resolveCursor(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver TaskEdge::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(TaskEdge)gql" }, std::move(params)); +} + +} // namespace object + +void AddTaskEdgeDetails(const std::shared_ptr& typeTaskEdge, const std::shared_ptr& schema) +{ + typeTaskEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Task)gql"sv)), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ItemCursor)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/TaskEdgeObject.h b/samples/today/nointrospection/TaskEdgeObject.h new file mode 100644 index 00000000..7a934280 --- /dev/null +++ b/samples/today/nointrospection/TaskEdgeObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef TASKEDGEOBJECT_H +#define TASKEDGEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::TaskEdgeHas { + +template +concept getNodeWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNode(std::move(params)) } }; +}; + +template +concept getNode = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNode() } }; +}; + +template +concept getCursorWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getCursor(std::move(params)) } }; +}; + +template +concept getCursor = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getCursor() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::TaskEdgeHas + +class TaskEdge + : public service::Object +{ +private: + service::AwaitableResolver resolveNode(service::ResolverParams&& params) const; + service::AwaitableResolver resolveCursor(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getNode(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getCursor(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getNode(service::FieldParams&& params) const final + { + if constexpr (methods::TaskEdgeHas::getNodeWithParams) + { + return { _pimpl->getNode(std::move(params)) }; + } + else if constexpr (methods::TaskEdgeHas::getNode) + { + return { _pimpl->getNode() }; + } + else + { + throw std::runtime_error(R"ex(TaskEdge::getNode is not implemented)ex"); + } + } + + service::AwaitableScalar getCursor(service::FieldParams&& params) const final + { + if constexpr (methods::TaskEdgeHas::getCursorWithParams) + { + return { _pimpl->getCursor(std::move(params)) }; + } + else if constexpr (methods::TaskEdgeHas::getCursor) + { + return { _pimpl->getCursor() }; + } + else + { + throw std::runtime_error(R"ex(TaskEdge::getCursor is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskEdgeHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskEdgeHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + TaskEdge(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + TaskEdge(std::shared_ptr pimpl) noexcept + : TaskEdge { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // TASKEDGEOBJECT_H diff --git a/samples/separate/TaskObject.cpp b/samples/today/nointrospection/TaskObject.cpp similarity index 50% rename from samples/separate/TaskObject.cpp rename to samples/today/nointrospection/TaskObject.cpp index 06e9492d..578ea5bf 100644 --- a/samples/separate/TaskObject.cpp +++ b/samples/today/nointrospection/TaskObject.cpp @@ -3,9 +3,11 @@ // WARNING! Do not edit this file manually, your changes will be overwritten. -#include "TodayObjects.h" +#include "TaskObject.h" -#include "graphqlservice/introspection/Introspection.h" +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" #include #include @@ -18,81 +20,87 @@ using namespace std::literals; namespace graphql::today { namespace object { -Task::Task() - : service::Object({ - "Node", - "UnionType", - "Task" - }, { +Task::Task(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Task::getTypeNames() const noexcept +{ + return { + R"gql(Node)gql"sv, + R"gql(UnionType)gql"sv, + R"gql(Task)gql"sv + }; +} + +service::ResolverMap Task::getResolvers() const noexcept +{ + return { { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, { R"gql(title)gql"sv, [this](service::ResolverParams&& params) { return resolveTitle(std::move(params)); } }, { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, { R"gql(isComplete)gql"sv, [this](service::ResolverParams&& params) { return resolveIsComplete(std::move(params)); } } - }) + }; +} + +void Task::beginSelectionSet(const service::SelectionSetParams& params) const { + _pimpl->beginSelectionSet(params); } -service::FieldResult Task::getId(service::FieldParams&&) const +void Task::endSelectionSet(const service::SelectionSetParams& params) const { - throw std::runtime_error(R"ex(Task::getId is not implemented)ex"); + _pimpl->endSelectionSet(params); } -std::future Task::resolveId(service::ResolverParams&& params) +service::AwaitableResolver Task::resolveId(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult> Task::getTitle(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Task::getTitle is not implemented)ex"); -} - -std::future Task::resolveTitle(service::ResolverParams&& params) +service::AwaitableResolver Task::resolveTitle(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getTitle(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getTitle(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Task::getIsComplete(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Task::getIsComplete is not implemented)ex"); + return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Task::resolveIsComplete(service::ResolverParams&& params) +service::AwaitableResolver Task::resolveIsComplete(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getIsComplete(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getIsComplete(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); - return service::ModifiedResult::convert(std::move(result), std::move(params)); + return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Task::resolve_typename(service::ResolverParams&& params) +service::AwaitableResolver Task::resolve_typename(service::ResolverParams&& params) const { - return service::ModifiedResult::convert(response::StringType{ R"gql(Task)gql" }, std::move(params)); + return service::ModifiedResult::convert(std::string{ R"gql(Task)gql" }, std::move(params)); } } // namespace object -void AddTaskDetails(std::shared_ptr typeTask, const std::shared_ptr& schema) +void AddTaskDetails(const std::shared_ptr& typeTask, const std::shared_ptr& schema) { typeTask->AddInterfaces({ std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) }); typeTask->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(title)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(isComplete)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))), + schema::Field::Make(R"gql(title)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(isComplete)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))) }); } diff --git a/samples/today/nointrospection/TaskObject.h b/samples/today/nointrospection/TaskObject.h new file mode 100644 index 00000000..b0746bd8 --- /dev/null +++ b/samples/today/nointrospection/TaskObject.h @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef TASKOBJECT_H +#define TASKOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace implements { + +template +concept TaskIs = std::is_same_v || std::is_same_v; + +} // namespace implements + +namespace methods::TaskHas { + +template +concept getIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getId(std::move(params)) } }; +}; + +template +concept getId = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getId() } }; +}; + +template +concept getTitleWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getTitle(std::move(params)) } }; +}; + +template +concept getTitle = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getTitle() } }; +}; + +template +concept getIsCompleteWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getIsComplete(std::move(params)) } }; +}; + +template +concept getIsComplete = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getIsComplete() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::TaskHas + +class Task + : public service::Object +{ +private: + service::AwaitableResolver resolveId(service::ResolverParams&& params) const; + service::AwaitableResolver resolveTitle(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIsComplete(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getId(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getTitle(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getIsComplete(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getId(service::FieldParams&& params) const final + { + if constexpr (methods::TaskHas::getIdWithParams) + { + return { _pimpl->getId(std::move(params)) }; + } + else if constexpr (methods::TaskHas::getId) + { + return { _pimpl->getId() }; + } + else + { + throw std::runtime_error(R"ex(Task::getId is not implemented)ex"); + } + } + + service::AwaitableScalar> getTitle(service::FieldParams&& params) const final + { + if constexpr (methods::TaskHas::getTitleWithParams) + { + return { _pimpl->getTitle(std::move(params)) }; + } + else if constexpr (methods::TaskHas::getTitle) + { + return { _pimpl->getTitle() }; + } + else + { + throw std::runtime_error(R"ex(Task::getTitle is not implemented)ex"); + } + } + + service::AwaitableScalar getIsComplete(service::FieldParams&& params) const final + { + if constexpr (methods::TaskHas::getIsCompleteWithParams) + { + return { _pimpl->getIsComplete(std::move(params)) }; + } + else if constexpr (methods::TaskHas::getIsComplete) + { + return { _pimpl->getIsComplete() }; + } + else + { + throw std::runtime_error(R"ex(Task::getIsComplete is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Task(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Node; + + // Unions which include this type + friend UnionType; + + template + static constexpr bool implements() noexcept + { + return implements::TaskIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Task(std::shared_ptr pimpl) noexcept + : Task { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // TASKOBJECT_H diff --git a/samples/separate_nointrospection/TodaySchema.cpp b/samples/today/nointrospection/TodaySchema.cpp similarity index 78% rename from samples/separate_nointrospection/TodaySchema.cpp rename to samples/today/nointrospection/TodaySchema.cpp index a80582b6..30d1db46 100644 --- a/samples/separate_nointrospection/TodaySchema.cpp +++ b/samples/today/nointrospection/TodaySchema.cpp @@ -3,9 +3,13 @@ // WARNING! Do not edit this file manually, your changes will be overwritten. -#include "TodayObjects.h" +#include "QueryObject.h" +#include "MutationObject.h" +#include "SubscriptionObject.h" -#include "graphqlservice/introspection/Introspection.h" +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" #include #include @@ -22,10 +26,10 @@ namespace graphql { namespace service { static const std::array s_namesTaskState = { - "New"sv, - "Started"sv, - "Complete"sv, - "Unassigned"sv + R"gql(New)gql"sv, + R"gql(Started)gql"sv, + R"gql(Complete)gql"sv, + R"gql(Unassigned)gql"sv }; template <> @@ -33,33 +37,49 @@ today::TaskState ModifiedArgument::convert(const response::Val { if (!value.maybe_enum()) { - throw service::schema_exception { { "not a valid TaskState value" } }; + throw service::schema_exception { { R"ex(not a valid TaskState value)ex" } }; } - const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.get()); + const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.get()); if (itr == s_namesTaskState.cend()) { - throw service::schema_exception { { "not a valid TaskState value" } }; + throw service::schema_exception { { R"ex(not a valid TaskState value)ex" } }; } return static_cast(itr - s_namesTaskState.cbegin()); } template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) +service::AwaitableResolver ModifiedResult::convert(service::AwaitableScalar result, ResolverParams params) { return resolve(std::move(result), std::move(params), [](today::TaskState value, const ResolverParams&) { response::Value result(response::Type::EnumValue); - result.set(response::StringType { s_namesTaskState[static_cast(value)] }); + result.set(std::string { s_namesTaskState[static_cast(value)] }); return result; }); } +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid TaskState value)ex" } }; + } + + const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.get()); + + if (itr == s_namesTaskState.cend()) + { + throw service::schema_exception { { R"ex(not a valid TaskState value)ex" } }; + } +} + template <> today::CompleteTaskInput ModifiedArgument::convert(const response::Value& value) { @@ -76,11 +96,11 @@ today::CompleteTaskInput ModifiedArgument::convert(con auto valueId = service::ModifiedArgument::require("id", value); auto valueTestTaskState = service::ModifiedArgument::require("testTaskState", value); - auto pairIsComplete = service::ModifiedArgument::find("isComplete", value); + auto pairIsComplete = service::ModifiedArgument::find("isComplete", value); auto valueIsComplete = (pairIsComplete.second ? std::move(pairIsComplete.first) - : service::ModifiedArgument::require("isComplete", defaultValue)); - auto valueClientMutationId = service::ModifiedArgument::require("clientMutationId", value); + : service::ModifiedArgument::require("isComplete", defaultValue)); + auto valueClientMutationId = service::ModifiedArgument::require("clientMutationId", value); return { std::move(valueId), @@ -154,8 +174,8 @@ Operations::Operations(std::shared_ptr query, std::shared_ptr& schema) { - schema->AddType(R"gql(ItemCursor)gql"sv, schema::ScalarType::Make(R"gql(ItemCursor)gql"sv, R"md()md")); - schema->AddType(R"gql(DateTime)gql"sv, schema::ScalarType::Make(R"gql(DateTime)gql"sv, R"md()md")); + schema->AddType(R"gql(ItemCursor)gql"sv, schema::ScalarType::Make(R"gql(ItemCursor)gql"sv, R"md()md", R"url()url"sv)); + schema->AddType(R"gql(DateTime)gql"sv, schema::ScalarType::Make(R"gql(DateTime)gql"sv, R"md()md", R"url()url"sv)); auto typeTaskState = schema::EnumType::Make(R"gql(TaskState)gql"sv, R"md()md"sv); schema->AddType(R"gql(TaskState)gql"sv, typeTaskState); auto typeCompleteTaskInput = schema::InputObjectType::Make(R"gql(CompleteTaskInput)gql"sv, R"md()md"sv); @@ -168,81 +188,75 @@ void AddTypesToSchema(const std::shared_ptr& schema) schema->AddType(R"gql(SecondNestedInput)gql"sv, typeSecondNestedInput); auto typeFirstNestedInput = schema::InputObjectType::Make(R"gql(FirstNestedInput)gql"sv, R"md()md"sv); schema->AddType(R"gql(FirstNestedInput)gql"sv, typeFirstNestedInput); - auto typeUnionType = schema::UnionType::Make(R"gql(UnionType)gql"sv, R"md()md"sv); - schema->AddType(R"gql(UnionType)gql"sv, typeUnionType); auto typeNode = schema::InterfaceType::Make(R"gql(Node)gql"sv, R"md()md"sv); schema->AddType(R"gql(Node)gql"sv, typeNode); - auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md()md"); + auto typeUnionType = schema::UnionType::Make(R"gql(UnionType)gql"sv, R"md()md"sv); + schema->AddType(R"gql(UnionType)gql"sv, typeUnionType); + auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md()md"sv); schema->AddType(R"gql(Query)gql"sv, typeQuery); - auto typePageInfo = schema::ObjectType::Make(R"gql(PageInfo)gql"sv, R"md()md"); + auto typePageInfo = schema::ObjectType::Make(R"gql(PageInfo)gql"sv, R"md()md"sv); schema->AddType(R"gql(PageInfo)gql"sv, typePageInfo); - auto typeAppointmentEdge = schema::ObjectType::Make(R"gql(AppointmentEdge)gql"sv, R"md()md"); + auto typeAppointmentEdge = schema::ObjectType::Make(R"gql(AppointmentEdge)gql"sv, R"md()md"sv); schema->AddType(R"gql(AppointmentEdge)gql"sv, typeAppointmentEdge); - auto typeAppointmentConnection = schema::ObjectType::Make(R"gql(AppointmentConnection)gql"sv, R"md()md"); + auto typeAppointmentConnection = schema::ObjectType::Make(R"gql(AppointmentConnection)gql"sv, R"md()md"sv); schema->AddType(R"gql(AppointmentConnection)gql"sv, typeAppointmentConnection); - auto typeTaskEdge = schema::ObjectType::Make(R"gql(TaskEdge)gql"sv, R"md()md"); + auto typeTaskEdge = schema::ObjectType::Make(R"gql(TaskEdge)gql"sv, R"md()md"sv); schema->AddType(R"gql(TaskEdge)gql"sv, typeTaskEdge); - auto typeTaskConnection = schema::ObjectType::Make(R"gql(TaskConnection)gql"sv, R"md()md"); + auto typeTaskConnection = schema::ObjectType::Make(R"gql(TaskConnection)gql"sv, R"md()md"sv); schema->AddType(R"gql(TaskConnection)gql"sv, typeTaskConnection); - auto typeFolderEdge = schema::ObjectType::Make(R"gql(FolderEdge)gql"sv, R"md()md"); + auto typeFolderEdge = schema::ObjectType::Make(R"gql(FolderEdge)gql"sv, R"md()md"sv); schema->AddType(R"gql(FolderEdge)gql"sv, typeFolderEdge); - auto typeFolderConnection = schema::ObjectType::Make(R"gql(FolderConnection)gql"sv, R"md()md"); + auto typeFolderConnection = schema::ObjectType::Make(R"gql(FolderConnection)gql"sv, R"md()md"sv); schema->AddType(R"gql(FolderConnection)gql"sv, typeFolderConnection); - auto typeCompleteTaskPayload = schema::ObjectType::Make(R"gql(CompleteTaskPayload)gql"sv, R"md()md"); + auto typeCompleteTaskPayload = schema::ObjectType::Make(R"gql(CompleteTaskPayload)gql"sv, R"md()md"sv); schema->AddType(R"gql(CompleteTaskPayload)gql"sv, typeCompleteTaskPayload); - auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"); + auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"sv); schema->AddType(R"gql(Mutation)gql"sv, typeMutation); - auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"); + auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"sv); schema->AddType(R"gql(Subscription)gql"sv, typeSubscription); - auto typeAppointment = schema::ObjectType::Make(R"gql(Appointment)gql"sv, R"md()md"); + auto typeAppointment = schema::ObjectType::Make(R"gql(Appointment)gql"sv, R"md()md"sv); schema->AddType(R"gql(Appointment)gql"sv, typeAppointment); - auto typeTask = schema::ObjectType::Make(R"gql(Task)gql"sv, R"md()md"); + auto typeTask = schema::ObjectType::Make(R"gql(Task)gql"sv, R"md()md"sv); schema->AddType(R"gql(Task)gql"sv, typeTask); - auto typeFolder = schema::ObjectType::Make(R"gql(Folder)gql"sv, R"md()md"); + auto typeFolder = schema::ObjectType::Make(R"gql(Folder)gql"sv, R"md()md"sv); schema->AddType(R"gql(Folder)gql"sv, typeFolder); - auto typeNestedType = schema::ObjectType::Make(R"gql(NestedType)gql"sv, R"md()md"); + auto typeNestedType = schema::ObjectType::Make(R"gql(NestedType)gql"sv, R"md()md"sv); schema->AddType(R"gql(NestedType)gql"sv, typeNestedType); - auto typeExpensive = schema::ObjectType::Make(R"gql(Expensive)gql"sv, R"md()md"); + auto typeExpensive = schema::ObjectType::Make(R"gql(Expensive)gql"sv, R"md()md"sv); schema->AddType(R"gql(Expensive)gql"sv, typeExpensive); typeTaskState->AddEnumValues({ { service::s_namesTaskState[static_cast(today::TaskState::New)], R"md()md"sv, std::nullopt }, { service::s_namesTaskState[static_cast(today::TaskState::Started)], R"md()md"sv, std::nullopt }, { service::s_namesTaskState[static_cast(today::TaskState::Complete)], R"md()md"sv, std::nullopt }, - { service::s_namesTaskState[static_cast(today::TaskState::Unassigned)], R"md()md"sv, std::make_optional(R"md(Need to deprecate an [enum value](http://spec.graphql.org/June2018/#sec-Deprecation))md"sv) } + { service::s_namesTaskState[static_cast(today::TaskState::Unassigned)], R"md()md"sv, std::make_optional(R"md(Need to deprecate an [enum value](https://spec.graphql.org/October2021/#sec-Schema-Introspection.Deprecation))md"sv) } }); typeCompleteTaskInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, schema->LookupType("TaskState"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(isComplete)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(true)gql"sv), - schema::InputValue::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv), + schema::InputValue::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, schema->LookupType(R"gql(TaskState)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(isComplete)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Boolean)gql"sv), R"gql(true)gql"sv), + schema::InputValue::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql()gql"sv) }); typeThirdNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv) }); typeFourthNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv) }); typeSecondNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ThirdNestedInput")), R"gql()gql"sv) + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv), + schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ThirdNestedInput)gql"sv)), R"gql()gql"sv) }); typeFirstNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(second)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("SecondNestedInput")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ThirdNestedInput")), R"gql()gql"sv) + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv), + schema::InputValue::Make(R"gql(second)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(SecondNestedInput)gql"sv)), R"gql()gql"sv), + schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ThirdNestedInput)gql"sv)), R"gql()gql"sv) }); - typeUnionType->AddPossibleTypes({ - schema->LookupType(R"gql(Appointment)gql"sv), - schema->LookupType(R"gql(Task)gql"sv), - schema->LookupType(R"gql(Folder)gql"sv) - }); + AddNodeDetails(typeNode, schema); - typeNode->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) - }); + AddUnionTypeDetails(typeUnionType, schema); AddQueryDetails(typeQuery, schema); AddPageInfoDetails(typePageInfo, schema); @@ -263,37 +277,35 @@ void AddTypesToSchema(const std::shared_ptr& schema) schema->AddDirective(schema::Directive::Make(R"gql(id)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::FIELD_DEFINITION - })); - schema->AddDirective(schema::Directive::Make(R"gql(subscriptionTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::SUBSCRIPTION - }, { - schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) - })); + }, {}, false)); schema->AddDirective(schema::Directive::Make(R"gql(queryTag)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::QUERY }, { - schema::InputValue::Make(R"gql(query)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); + schema::InputValue::Make(R"gql(query)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }, false)); schema->AddDirective(schema::Directive::Make(R"gql(fieldTag)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::FIELD }, { - schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); + schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }, false)); schema->AddDirective(schema::Directive::Make(R"gql(fragmentDefinitionTag)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::FRAGMENT_DEFINITION }, { - schema::InputValue::Make(R"gql(fragmentDefinition)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); + schema::InputValue::Make(R"gql(fragmentDefinition)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }, false)); schema->AddDirective(schema::Directive::Make(R"gql(fragmentSpreadTag)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::FRAGMENT_SPREAD }, { - schema::InputValue::Make(R"gql(fragmentSpread)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); + schema::InputValue::Make(R"gql(fragmentSpread)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }, false)); schema->AddDirective(schema::Directive::Make(R"gql(inlineFragmentTag)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::INLINE_FRAGMENT }, { - schema::InputValue::Make(R"gql(inlineFragment)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); + schema::InputValue::Make(R"gql(inlineFragment)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }, false)); + schema->AddDirective(schema::Directive::Make(R"gql(repeatableOnField)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD + }, {}, true)); schema->AddQueryType(typeQuery); schema->AddMutationType(typeMutation); @@ -307,7 +319,7 @@ std::shared_ptr GetSchema() if (!schema) { - schema = std::make_shared(true); + schema = std::make_shared(true, R"md()md"sv); introspection::AddTypesToSchema(schema); AddTypesToSchema(schema); s_wpSchema = schema; diff --git a/samples/today/nointrospection/TodaySchema.h b/samples/today/nointrospection/TodaySchema.h new file mode 100644 index 00000000..bb0834b2 --- /dev/null +++ b/samples/today/nointrospection/TodaySchema.h @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef TODAYSCHEMA_H +#define TODAYSCHEMA_H + +#include "graphqlservice/internal/Schema.h" + +// Check if the library version is compatible with schemagen 4.0.0 +static_assert(graphql::internal::MajorVersion == 4, "regenerate with schemagen: major version mismatch"); +static_assert(graphql::internal::MinorVersion == 0, "regenerate with schemagen: minor version mismatch"); + +#include +#include +#include + +namespace graphql { +namespace today { + +enum class TaskState +{ + New, + Started, + Complete, + Unassigned +}; + +struct CompleteTaskInput +{ + response::IdType id {}; + std::optional testTaskState {}; + std::optional isComplete {}; + std::optional clientMutationId {}; +}; + +struct ThirdNestedInput +{ + response::IdType id {}; +}; + +struct FourthNestedInput +{ + response::IdType id {}; +}; + +struct SecondNestedInput +{ + response::IdType id {}; + ThirdNestedInput third {}; +}; + +struct FirstNestedInput +{ + response::IdType id {}; + SecondNestedInput second {}; + ThirdNestedInput third {}; +}; + +namespace object { + +class Node; + +class UnionType; + +class Query; +class PageInfo; +class AppointmentEdge; +class AppointmentConnection; +class TaskEdge; +class TaskConnection; +class FolderEdge; +class FolderConnection; +class CompleteTaskPayload; +class Mutation; +class Subscription; +class Appointment; +class Task; +class Folder; +class NestedType; +class Expensive; + +} // namespace object + +class Operations + : public service::Request +{ +public: + explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription); + + template + explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription) + : Operations { std::make_shared(std::move(query)), std::make_shared(std::move(mutation)), std::make_shared(std::move(subscription)) } + { + } + +private: + std::shared_ptr _query; + std::shared_ptr _mutation; + std::shared_ptr _subscription; +}; + +void AddNodeDetails(const std::shared_ptr& typeNode, const std::shared_ptr& schema); + +void AddUnionTypeDetails(const std::shared_ptr& typeUnionType, const std::shared_ptr& schema); + +void AddQueryDetails(const std::shared_ptr& typeQuery, const std::shared_ptr& schema); +void AddPageInfoDetails(const std::shared_ptr& typePageInfo, const std::shared_ptr& schema); +void AddAppointmentEdgeDetails(const std::shared_ptr& typeAppointmentEdge, const std::shared_ptr& schema); +void AddAppointmentConnectionDetails(const std::shared_ptr& typeAppointmentConnection, const std::shared_ptr& schema); +void AddTaskEdgeDetails(const std::shared_ptr& typeTaskEdge, const std::shared_ptr& schema); +void AddTaskConnectionDetails(const std::shared_ptr& typeTaskConnection, const std::shared_ptr& schema); +void AddFolderEdgeDetails(const std::shared_ptr& typeFolderEdge, const std::shared_ptr& schema); +void AddFolderConnectionDetails(const std::shared_ptr& typeFolderConnection, const std::shared_ptr& schema); +void AddCompleteTaskPayloadDetails(const std::shared_ptr& typeCompleteTaskPayload, const std::shared_ptr& schema); +void AddMutationDetails(const std::shared_ptr& typeMutation, const std::shared_ptr& schema); +void AddSubscriptionDetails(const std::shared_ptr& typeSubscription, const std::shared_ptr& schema); +void AddAppointmentDetails(const std::shared_ptr& typeAppointment, const std::shared_ptr& schema); +void AddTaskDetails(const std::shared_ptr& typeTask, const std::shared_ptr& schema); +void AddFolderDetails(const std::shared_ptr& typeFolder, const std::shared_ptr& schema); +void AddNestedTypeDetails(const std::shared_ptr& typeNestedType, const std::shared_ptr& schema); +void AddExpensiveDetails(const std::shared_ptr& typeExpensive, const std::shared_ptr& schema); + +std::shared_ptr GetSchema(); + +} // namespace today +} // namespace graphql + +#endif // TODAYSCHEMA_H diff --git a/samples/today/nointrospection/UnionTypeObject.cpp b/samples/today/nointrospection/UnionTypeObject.cpp new file mode 100644 index 00000000..7955b900 --- /dev/null +++ b/samples/today/nointrospection/UnionTypeObject.cpp @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "UnionTypeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +UnionType::UnionType(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void UnionType::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void UnionType::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddUnionTypeDetails(const std::shared_ptr& typeUnionType, const std::shared_ptr& schema) +{ + typeUnionType->AddPossibleTypes({ + schema->LookupType(R"gql(Appointment)gql"sv), + schema->LookupType(R"gql(Task)gql"sv), + schema->LookupType(R"gql(Folder)gql"sv) + }); +} + +} // namespace graphql::today diff --git a/samples/today/nointrospection/UnionTypeObject.h b/samples/today/nointrospection/UnionTypeObject.h new file mode 100644 index 00000000..4e1ec759 --- /dev/null +++ b/samples/today/nointrospection/UnionTypeObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef UNIONTYPEOBJECT_H +#define UNIONTYPEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class UnionType + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + UnionType(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + UnionType(std::shared_ptr pimpl) noexcept + : UnionType { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "UnionType is not implemented"); + } +}; + +} // namespace graphql::today::object + +#endif // UNIONTYPEOBJECT_H diff --git a/samples/separate_nointrospection/today_schema_files b/samples/today/nointrospection/today_nointrospection_schema_files similarity index 91% rename from samples/separate_nointrospection/today_schema_files rename to samples/today/nointrospection/today_nointrospection_schema_files index f1fb1229..a9ed9ecf 100644 --- a/samples/separate_nointrospection/today_schema_files +++ b/samples/today/nointrospection/today_nointrospection_schema_files @@ -1,4 +1,6 @@ TodaySchema.cpp +NodeObject.cpp +UnionTypeObject.cpp QueryObject.cpp PageInfoObject.cpp AppointmentEdgeObject.cpp diff --git a/samples/today/sample.cpp b/samples/today/sample.cpp index 376a7300..2c2e9f97 100644 --- a/samples/today/sample.cpp +++ b/samples/today/sample.cpp @@ -84,12 +84,8 @@ int main(int argc, char** argv) std::cout << "Executing query..." << std::endl; - std::cout << response::toJSON(service - ->resolve(nullptr, - query, - ((argc > 2) ? argv[2] : ""), - response::Value(response::Type::Map)) - .get()) + std::cout << response::toJSON( + service->resolve({ query, ((argc > 2) ? argv[2] : "") }).get()) << std::endl; } catch (const std::runtime_error& ex) diff --git a/samples/schema.today.graphql b/samples/today/schema.today.graphql similarity index 85% rename from samples/schema.today.graphql rename to samples/today/schema.today.graphql index 0e2bb3e8..53056ab0 100644 --- a/samples/schema.today.graphql +++ b/samples/today/schema.today.graphql @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +"Test Schema based on a dashboard showing daily appointments, tasks, and email folders with unread counts." schema { query: Query mutation: Mutation @@ -95,23 +96,29 @@ type Mutation { setFloat(value: Float!): Float! } + """ + + Subscription type: + + 2nd line... + 3rd line goes here! + + """ type Subscription { nextAppointmentChange : Appointment @deprecated( - reason:"""Need to deprecate a [field](http://spec.graphql.org/June2018/#sec-Deprecation)""" + reason:"""Need to deprecate a [field](https://spec.graphql.org/October2021/#sec-Schema-Introspection.Deprecation)""" ) nodeChange(id: ID!): Node! } -directive @subscriptionTag(field: String) on SUBSCRIPTION - -scalar DateTime +scalar DateTime @specifiedBy(url: "https://en.wikipedia.org/wiki/ISO_8601") enum TaskState { New Started Complete Unassigned @deprecated( - reason:"""Need to deprecate an [enum value](http://spec.graphql.org/June2018/#sec-Deprecation)""" + reason:"""Need to deprecate an [enum value](https://spec.graphql.org/October2021/#sec-Schema-Introspection.Deprecation)""" ) } @@ -142,6 +149,7 @@ directive @fieldTag(field: String!) on FIELD directive @fragmentDefinitionTag(fragmentDefinition: String!) on FRAGMENT_DEFINITION directive @fragmentSpreadTag(fragmentSpread: String!) on FRAGMENT_SPREAD directive @inlineFragmentTag(inlineFragment: String!) on INLINE_FRAGMENT +directive @repeatableOnField repeatable on FIELD "Infinitely nestable type which can be used with nested fragments to test directive handling" type NestedType { diff --git a/samples/today/schema/AppointmentConnectionObject.cpp b/samples/today/schema/AppointmentConnectionObject.cpp new file mode 100644 index 00000000..19842a49 --- /dev/null +++ b/samples/today/schema/AppointmentConnectionObject.cpp @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "AppointmentConnectionObject.h" +#include "PageInfoObject.h" +#include "AppointmentEdgeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +AppointmentConnection::AppointmentConnection(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames AppointmentConnection::getTypeNames() const noexcept +{ + return { + R"gql(AppointmentConnection)gql"sv + }; +} + +service::ResolverMap AppointmentConnection::getResolvers() const noexcept +{ + return { + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void AppointmentConnection::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void AppointmentConnection::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver AppointmentConnection::resolveEdges(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver AppointmentConnection::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(AppointmentConnection)gql" }, std::move(params)); +} + +} // namespace object + +void AddAppointmentConnectionDetails(const std::shared_ptr& typeAppointmentConnection, const std::shared_ptr& schema) +{ + typeAppointmentConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PageInfo)gql"sv))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(AppointmentEdge)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/AppointmentConnectionObject.h b/samples/today/schema/AppointmentConnectionObject.h new file mode 100644 index 00000000..8c065063 --- /dev/null +++ b/samples/today/schema/AppointmentConnectionObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef APPOINTMENTCONNECTIONOBJECT_H +#define APPOINTMENTCONNECTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::AppointmentConnectionHas { + +template +concept getPageInfoWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getPageInfo(std::move(params)) } }; +}; + +template +concept getPageInfo = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getPageInfo() } }; +}; + +template +concept getEdgesWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject>>> { impl.getEdges(std::move(params)) } }; +}; + +template +concept getEdges = requires (TImpl impl) +{ + { service::AwaitableObject>>> { impl.getEdges() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::AppointmentConnectionHas + +class AppointmentConnection + : public service::Object +{ +private: + service::AwaitableResolver resolvePageInfo(service::ResolverParams&& params) const; + service::AwaitableResolver resolveEdges(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getPageInfo(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>>> getEdges(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getPageInfo(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentConnectionHas::getPageInfoWithParams) + { + return { _pimpl->getPageInfo(std::move(params)) }; + } + else if constexpr (methods::AppointmentConnectionHas::getPageInfo) + { + return { _pimpl->getPageInfo() }; + } + else + { + throw std::runtime_error(R"ex(AppointmentConnection::getPageInfo is not implemented)ex"); + } + } + + service::AwaitableObject>>> getEdges(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentConnectionHas::getEdgesWithParams) + { + return { _pimpl->getEdges(std::move(params)) }; + } + else if constexpr (methods::AppointmentConnectionHas::getEdges) + { + return { _pimpl->getEdges() }; + } + else + { + throw std::runtime_error(R"ex(AppointmentConnection::getEdges is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentConnectionHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentConnectionHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + AppointmentConnection(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + AppointmentConnection(std::shared_ptr pimpl) noexcept + : AppointmentConnection { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // APPOINTMENTCONNECTIONOBJECT_H diff --git a/samples/today/schema/AppointmentEdgeObject.cpp b/samples/today/schema/AppointmentEdgeObject.cpp new file mode 100644 index 00000000..ea507e43 --- /dev/null +++ b/samples/today/schema/AppointmentEdgeObject.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "AppointmentEdgeObject.h" +#include "AppointmentObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +AppointmentEdge::AppointmentEdge(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames AppointmentEdge::getTypeNames() const noexcept +{ + return { + R"gql(AppointmentEdge)gql"sv + }; +} + +service::ResolverMap AppointmentEdge::getResolvers() const noexcept +{ + return { + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void AppointmentEdge::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void AppointmentEdge::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver AppointmentEdge::resolveNode(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver AppointmentEdge::resolveCursor(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver AppointmentEdge::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(AppointmentEdge)gql" }, std::move(params)); +} + +} // namespace object + +void AddAppointmentEdgeDetails(const std::shared_ptr& typeAppointmentEdge, const std::shared_ptr& schema) +{ + typeAppointmentEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Appointment)gql"sv)), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ItemCursor)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/AppointmentEdgeObject.h b/samples/today/schema/AppointmentEdgeObject.h new file mode 100644 index 00000000..205d2d3f --- /dev/null +++ b/samples/today/schema/AppointmentEdgeObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef APPOINTMENTEDGEOBJECT_H +#define APPOINTMENTEDGEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::AppointmentEdgeHas { + +template +concept getNodeWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNode(std::move(params)) } }; +}; + +template +concept getNode = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNode() } }; +}; + +template +concept getCursorWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getCursor(std::move(params)) } }; +}; + +template +concept getCursor = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getCursor() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::AppointmentEdgeHas + +class AppointmentEdge + : public service::Object +{ +private: + service::AwaitableResolver resolveNode(service::ResolverParams&& params) const; + service::AwaitableResolver resolveCursor(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getNode(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getCursor(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getNode(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentEdgeHas::getNodeWithParams) + { + return { _pimpl->getNode(std::move(params)) }; + } + else if constexpr (methods::AppointmentEdgeHas::getNode) + { + return { _pimpl->getNode() }; + } + else + { + throw std::runtime_error(R"ex(AppointmentEdge::getNode is not implemented)ex"); + } + } + + service::AwaitableScalar getCursor(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentEdgeHas::getCursorWithParams) + { + return { _pimpl->getCursor(std::move(params)) }; + } + else if constexpr (methods::AppointmentEdgeHas::getCursor) + { + return { _pimpl->getCursor() }; + } + else + { + throw std::runtime_error(R"ex(AppointmentEdge::getCursor is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentEdgeHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentEdgeHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + AppointmentEdge(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + AppointmentEdge(std::shared_ptr pimpl) noexcept + : AppointmentEdge { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // APPOINTMENTEDGEOBJECT_H diff --git a/samples/today/schema/AppointmentObject.cpp b/samples/today/schema/AppointmentObject.cpp new file mode 100644 index 00000000..474ee49b --- /dev/null +++ b/samples/today/schema/AppointmentObject.cpp @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "AppointmentObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Appointment::Appointment(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Appointment::getTypeNames() const noexcept +{ + return { + R"gql(Node)gql"sv, + R"gql(UnionType)gql"sv, + R"gql(Appointment)gql"sv + }; +} + +service::ResolverMap Appointment::getResolvers() const noexcept +{ + return { + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(when)gql"sv, [this](service::ResolverParams&& params) { return resolveWhen(std::move(params)); } }, + { R"gql(isNow)gql"sv, [this](service::ResolverParams&& params) { return resolveIsNow(std::move(params)); } }, + { R"gql(subject)gql"sv, [this](service::ResolverParams&& params) { return resolveSubject(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(forceError)gql"sv, [this](service::ResolverParams&& params) { return resolveForceError(std::move(params)); } } + }; +} + +void Appointment::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Appointment::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Appointment::resolveId(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Appointment::resolveWhen(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getWhen(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Appointment::resolveSubject(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getSubject(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Appointment::resolveIsNow(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getIsNow(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Appointment::resolveForceError(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getForceError(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Appointment::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Appointment)gql" }, std::move(params)); +} + +} // namespace object + +void AddAppointmentDetails(const std::shared_ptr& typeAppointment, const std::shared_ptr& schema) +{ + typeAppointment->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) + }); + typeAppointment->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))), + schema::Field::Make(R"gql(when)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(DateTime)gql"sv)), + schema::Field::Make(R"gql(subject)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(isNow)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))), + schema::Field::Make(R"gql(forceError)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/AppointmentObject.h b/samples/today/schema/AppointmentObject.h new file mode 100644 index 00000000..22817647 --- /dev/null +++ b/samples/today/schema/AppointmentObject.h @@ -0,0 +1,264 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef APPOINTMENTOBJECT_H +#define APPOINTMENTOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace implements { + +template +concept AppointmentIs = std::is_same_v || std::is_same_v; + +} // namespace implements + +namespace methods::AppointmentHas { + +template +concept getIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getId(std::move(params)) } }; +}; + +template +concept getId = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getId() } }; +}; + +template +concept getWhenWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getWhen(std::move(params)) } }; +}; + +template +concept getWhen = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getWhen() } }; +}; + +template +concept getSubjectWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getSubject(std::move(params)) } }; +}; + +template +concept getSubject = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getSubject() } }; +}; + +template +concept getIsNowWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getIsNow(std::move(params)) } }; +}; + +template +concept getIsNow = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getIsNow() } }; +}; + +template +concept getForceErrorWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getForceError(std::move(params)) } }; +}; + +template +concept getForceError = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getForceError() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::AppointmentHas + +class Appointment + : public service::Object +{ +private: + service::AwaitableResolver resolveId(service::ResolverParams&& params) const; + service::AwaitableResolver resolveWhen(service::ResolverParams&& params) const; + service::AwaitableResolver resolveSubject(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIsNow(service::ResolverParams&& params) const; + service::AwaitableResolver resolveForceError(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getId(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getWhen(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getSubject(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getIsNow(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getForceError(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getId(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentHas::getIdWithParams) + { + return { _pimpl->getId(std::move(params)) }; + } + else if constexpr (methods::AppointmentHas::getId) + { + return { _pimpl->getId() }; + } + else + { + throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); + } + } + + service::AwaitableScalar> getWhen(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentHas::getWhenWithParams) + { + return { _pimpl->getWhen(std::move(params)) }; + } + else if constexpr (methods::AppointmentHas::getWhen) + { + return { _pimpl->getWhen() }; + } + else + { + throw std::runtime_error(R"ex(Appointment::getWhen is not implemented)ex"); + } + } + + service::AwaitableScalar> getSubject(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentHas::getSubjectWithParams) + { + return { _pimpl->getSubject(std::move(params)) }; + } + else if constexpr (methods::AppointmentHas::getSubject) + { + return { _pimpl->getSubject() }; + } + else + { + throw std::runtime_error(R"ex(Appointment::getSubject is not implemented)ex"); + } + } + + service::AwaitableScalar getIsNow(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentHas::getIsNowWithParams) + { + return { _pimpl->getIsNow(std::move(params)) }; + } + else if constexpr (methods::AppointmentHas::getIsNow) + { + return { _pimpl->getIsNow() }; + } + else + { + throw std::runtime_error(R"ex(Appointment::getIsNow is not implemented)ex"); + } + } + + service::AwaitableScalar> getForceError(service::FieldParams&& params) const final + { + if constexpr (methods::AppointmentHas::getForceErrorWithParams) + { + return { _pimpl->getForceError(std::move(params)) }; + } + else if constexpr (methods::AppointmentHas::getForceError) + { + return { _pimpl->getForceError() }; + } + else + { + throw std::runtime_error(R"ex(Appointment::getForceError is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AppointmentHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Appointment(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Node; + + // Unions which include this type + friend UnionType; + + template + static constexpr bool implements() noexcept + { + return implements::AppointmentIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Appointment(std::shared_ptr pimpl) noexcept + : Appointment { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // APPOINTMENTOBJECT_H diff --git a/samples/today/schema/CMakeLists.txt b/samples/today/schema/CMakeLists.txt new file mode 100644 index 00000000..0c6403ec --- /dev/null +++ b/samples/today/schema/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +# Normally this would be handled by find_package(cppgraphqlgen CONFIG). +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/cppgraphqlgen-functions.cmake) + +if(GRAPHQL_UPDATE_SAMPLES) + update_graphql_schema_files(today ../schema.today.graphql Today today --stubs) +endif() + +add_graphql_schema_target(today) diff --git a/samples/today/schema/CompleteTaskPayloadObject.cpp b/samples/today/schema/CompleteTaskPayloadObject.cpp new file mode 100644 index 00000000..bccfeca8 --- /dev/null +++ b/samples/today/schema/CompleteTaskPayloadObject.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "CompleteTaskPayloadObject.h" +#include "TaskObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +CompleteTaskPayload::CompleteTaskPayload(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames CompleteTaskPayload::getTypeNames() const noexcept +{ + return { + R"gql(CompleteTaskPayload)gql"sv + }; +} + +service::ResolverMap CompleteTaskPayload::getResolvers() const noexcept +{ + return { + { R"gql(task)gql"sv, [this](service::ResolverParams&& params) { return resolveTask(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(clientMutationId)gql"sv, [this](service::ResolverParams&& params) { return resolveClientMutationId(std::move(params)); } } + }; +} + +void CompleteTaskPayload::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void CompleteTaskPayload::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver CompleteTaskPayload::resolveTask(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getClientMutationId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(CompleteTaskPayload)gql" }, std::move(params)); +} + +} // namespace object + +void AddCompleteTaskPayloadDetails(const std::shared_ptr& typeCompleteTaskPayload, const std::shared_ptr& schema) +{ + typeCompleteTaskPayload->AddFields({ + schema::Field::Make(R"gql(task)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Task)gql"sv)), + schema::Field::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/CompleteTaskPayloadObject.h b/samples/today/schema/CompleteTaskPayloadObject.h new file mode 100644 index 00000000..3385815a --- /dev/null +++ b/samples/today/schema/CompleteTaskPayloadObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef COMPLETETASKPAYLOADOBJECT_H +#define COMPLETETASKPAYLOADOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::CompleteTaskPayloadHas { + +template +concept getTaskWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getTask(std::move(params)) } }; +}; + +template +concept getTask = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getTask() } }; +}; + +template +concept getClientMutationIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getClientMutationId(std::move(params)) } }; +}; + +template +concept getClientMutationId = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getClientMutationId() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::CompleteTaskPayloadHas + +class CompleteTaskPayload + : public service::Object +{ +private: + service::AwaitableResolver resolveTask(service::ResolverParams&& params) const; + service::AwaitableResolver resolveClientMutationId(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getTask(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getClientMutationId(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getTask(service::FieldParams&& params) const final + { + if constexpr (methods::CompleteTaskPayloadHas::getTaskWithParams) + { + return { _pimpl->getTask(std::move(params)) }; + } + else if constexpr (methods::CompleteTaskPayloadHas::getTask) + { + return { _pimpl->getTask() }; + } + else + { + throw std::runtime_error(R"ex(CompleteTaskPayload::getTask is not implemented)ex"); + } + } + + service::AwaitableScalar> getClientMutationId(service::FieldParams&& params) const final + { + if constexpr (methods::CompleteTaskPayloadHas::getClientMutationIdWithParams) + { + return { _pimpl->getClientMutationId(std::move(params)) }; + } + else if constexpr (methods::CompleteTaskPayloadHas::getClientMutationId) + { + return { _pimpl->getClientMutationId() }; + } + else + { + throw std::runtime_error(R"ex(CompleteTaskPayload::getClientMutationId is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::CompleteTaskPayloadHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::CompleteTaskPayloadHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + CompleteTaskPayload(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + CompleteTaskPayload(std::shared_ptr pimpl) noexcept + : CompleteTaskPayload { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // COMPLETETASKPAYLOADOBJECT_H diff --git a/samples/today/schema/ExpensiveObject.cpp b/samples/today/schema/ExpensiveObject.cpp new file mode 100644 index 00000000..55268ab3 --- /dev/null +++ b/samples/today/schema/ExpensiveObject.cpp @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "ExpensiveObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Expensive::Expensive(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Expensive::getTypeNames() const noexcept +{ + return { + R"gql(Expensive)gql"sv + }; +} + +service::ResolverMap Expensive::getResolvers() const noexcept +{ + return { + { R"gql(order)gql"sv, [this](service::ResolverParams&& params) { return resolveOrder(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void Expensive::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Expensive::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Expensive::resolveOrder(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getOrder(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Expensive::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Expensive)gql" }, std::move(params)); +} + +} // namespace object + +void AddExpensiveDetails(const std::shared_ptr& typeExpensive, const std::shared_ptr& schema) +{ + typeExpensive->AddFields({ + schema::Field::Make(R"gql(order)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/ExpensiveObject.h b/samples/today/schema/ExpensiveObject.h new file mode 100644 index 00000000..19c717e1 --- /dev/null +++ b/samples/today/schema/ExpensiveObject.h @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef EXPENSIVEOBJECT_H +#define EXPENSIVEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::ExpensiveHas { + +template +concept getOrderWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getOrder(std::move(params)) } }; +}; + +template +concept getOrder = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getOrder() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::ExpensiveHas + +class Expensive + : public service::Object +{ +private: + service::AwaitableResolver resolveOrder(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getOrder(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getOrder(service::FieldParams&& params) const final + { + if constexpr (methods::ExpensiveHas::getOrderWithParams) + { + return { _pimpl->getOrder(std::move(params)) }; + } + else if constexpr (methods::ExpensiveHas::getOrder) + { + return { _pimpl->getOrder() }; + } + else + { + throw std::runtime_error(R"ex(Expensive::getOrder is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::ExpensiveHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::ExpensiveHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Expensive(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Expensive(std::shared_ptr pimpl) noexcept + : Expensive { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // EXPENSIVEOBJECT_H diff --git a/samples/today/schema/FolderConnectionObject.cpp b/samples/today/schema/FolderConnectionObject.cpp new file mode 100644 index 00000000..8008268e --- /dev/null +++ b/samples/today/schema/FolderConnectionObject.cpp @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "FolderConnectionObject.h" +#include "PageInfoObject.h" +#include "FolderEdgeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +FolderConnection::FolderConnection(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames FolderConnection::getTypeNames() const noexcept +{ + return { + R"gql(FolderConnection)gql"sv + }; +} + +service::ResolverMap FolderConnection::getResolvers() const noexcept +{ + return { + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void FolderConnection::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void FolderConnection::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver FolderConnection::resolvePageInfo(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver FolderConnection::resolveEdges(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver FolderConnection::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(FolderConnection)gql" }, std::move(params)); +} + +} // namespace object + +void AddFolderConnectionDetails(const std::shared_ptr& typeFolderConnection, const std::shared_ptr& schema) +{ + typeFolderConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PageInfo)gql"sv))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(FolderEdge)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/FolderConnectionObject.h b/samples/today/schema/FolderConnectionObject.h new file mode 100644 index 00000000..cd92557b --- /dev/null +++ b/samples/today/schema/FolderConnectionObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef FOLDERCONNECTIONOBJECT_H +#define FOLDERCONNECTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::FolderConnectionHas { + +template +concept getPageInfoWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getPageInfo(std::move(params)) } }; +}; + +template +concept getPageInfo = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getPageInfo() } }; +}; + +template +concept getEdgesWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject>>> { impl.getEdges(std::move(params)) } }; +}; + +template +concept getEdges = requires (TImpl impl) +{ + { service::AwaitableObject>>> { impl.getEdges() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::FolderConnectionHas + +class FolderConnection + : public service::Object +{ +private: + service::AwaitableResolver resolvePageInfo(service::ResolverParams&& params) const; + service::AwaitableResolver resolveEdges(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getPageInfo(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>>> getEdges(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getPageInfo(service::FieldParams&& params) const final + { + if constexpr (methods::FolderConnectionHas::getPageInfoWithParams) + { + return { _pimpl->getPageInfo(std::move(params)) }; + } + else if constexpr (methods::FolderConnectionHas::getPageInfo) + { + return { _pimpl->getPageInfo() }; + } + else + { + throw std::runtime_error(R"ex(FolderConnection::getPageInfo is not implemented)ex"); + } + } + + service::AwaitableObject>>> getEdges(service::FieldParams&& params) const final + { + if constexpr (methods::FolderConnectionHas::getEdgesWithParams) + { + return { _pimpl->getEdges(std::move(params)) }; + } + else if constexpr (methods::FolderConnectionHas::getEdges) + { + return { _pimpl->getEdges() }; + } + else + { + throw std::runtime_error(R"ex(FolderConnection::getEdges is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderConnectionHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderConnectionHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + FolderConnection(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + FolderConnection(std::shared_ptr pimpl) noexcept + : FolderConnection { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // FOLDERCONNECTIONOBJECT_H diff --git a/samples/today/schema/FolderEdgeObject.cpp b/samples/today/schema/FolderEdgeObject.cpp new file mode 100644 index 00000000..b26cb3b0 --- /dev/null +++ b/samples/today/schema/FolderEdgeObject.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "FolderEdgeObject.h" +#include "FolderObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +FolderEdge::FolderEdge(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames FolderEdge::getTypeNames() const noexcept +{ + return { + R"gql(FolderEdge)gql"sv + }; +} + +service::ResolverMap FolderEdge::getResolvers() const noexcept +{ + return { + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void FolderEdge::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void FolderEdge::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver FolderEdge::resolveNode(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver FolderEdge::resolveCursor(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver FolderEdge::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(FolderEdge)gql" }, std::move(params)); +} + +} // namespace object + +void AddFolderEdgeDetails(const std::shared_ptr& typeFolderEdge, const std::shared_ptr& schema) +{ + typeFolderEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Folder)gql"sv)), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ItemCursor)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/FolderEdgeObject.h b/samples/today/schema/FolderEdgeObject.h new file mode 100644 index 00000000..65280232 --- /dev/null +++ b/samples/today/schema/FolderEdgeObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef FOLDEREDGEOBJECT_H +#define FOLDEREDGEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::FolderEdgeHas { + +template +concept getNodeWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNode(std::move(params)) } }; +}; + +template +concept getNode = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNode() } }; +}; + +template +concept getCursorWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getCursor(std::move(params)) } }; +}; + +template +concept getCursor = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getCursor() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::FolderEdgeHas + +class FolderEdge + : public service::Object +{ +private: + service::AwaitableResolver resolveNode(service::ResolverParams&& params) const; + service::AwaitableResolver resolveCursor(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getNode(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getCursor(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getNode(service::FieldParams&& params) const final + { + if constexpr (methods::FolderEdgeHas::getNodeWithParams) + { + return { _pimpl->getNode(std::move(params)) }; + } + else if constexpr (methods::FolderEdgeHas::getNode) + { + return { _pimpl->getNode() }; + } + else + { + throw std::runtime_error(R"ex(FolderEdge::getNode is not implemented)ex"); + } + } + + service::AwaitableScalar getCursor(service::FieldParams&& params) const final + { + if constexpr (methods::FolderEdgeHas::getCursorWithParams) + { + return { _pimpl->getCursor(std::move(params)) }; + } + else if constexpr (methods::FolderEdgeHas::getCursor) + { + return { _pimpl->getCursor() }; + } + else + { + throw std::runtime_error(R"ex(FolderEdge::getCursor is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderEdgeHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderEdgeHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + FolderEdge(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + FolderEdge(std::shared_ptr pimpl) noexcept + : FolderEdge { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // FOLDEREDGEOBJECT_H diff --git a/samples/today/schema/FolderObject.cpp b/samples/today/schema/FolderObject.cpp new file mode 100644 index 00000000..700f5414 --- /dev/null +++ b/samples/today/schema/FolderObject.cpp @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "FolderObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Folder::Folder(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Folder::getTypeNames() const noexcept +{ + return { + R"gql(Node)gql"sv, + R"gql(UnionType)gql"sv, + R"gql(Folder)gql"sv + }; +} + +service::ResolverMap Folder::getResolvers() const noexcept +{ + return { + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(unreadCount)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCount(std::move(params)); } } + }; +} + +void Folder::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Folder::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Folder::resolveId(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Folder::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Folder::resolveUnreadCount(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getUnreadCount(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Folder::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Folder)gql" }, std::move(params)); +} + +} // namespace object + +void AddFolderDetails(const std::shared_ptr& typeFolder, const std::shared_ptr& schema) +{ + typeFolder->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) + }); + typeFolder->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))), + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(unreadCount)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/FolderObject.h b/samples/today/schema/FolderObject.h new file mode 100644 index 00000000..9d2cbbfc --- /dev/null +++ b/samples/today/schema/FolderObject.h @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef FOLDEROBJECT_H +#define FOLDEROBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace implements { + +template +concept FolderIs = std::is_same_v || std::is_same_v; + +} // namespace implements + +namespace methods::FolderHas { + +template +concept getIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getId(std::move(params)) } }; +}; + +template +concept getId = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getId() } }; +}; + +template +concept getNameWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getName(std::move(params)) } }; +}; + +template +concept getName = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getName() } }; +}; + +template +concept getUnreadCountWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getUnreadCount(std::move(params)) } }; +}; + +template +concept getUnreadCount = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getUnreadCount() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::FolderHas + +class Folder + : public service::Object +{ +private: + service::AwaitableResolver resolveId(service::ResolverParams&& params) const; + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveUnreadCount(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getId(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getName(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getUnreadCount(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getId(service::FieldParams&& params) const final + { + if constexpr (methods::FolderHas::getIdWithParams) + { + return { _pimpl->getId(std::move(params)) }; + } + else if constexpr (methods::FolderHas::getId) + { + return { _pimpl->getId() }; + } + else + { + throw std::runtime_error(R"ex(Folder::getId is not implemented)ex"); + } + } + + service::AwaitableScalar> getName(service::FieldParams&& params) const final + { + if constexpr (methods::FolderHas::getNameWithParams) + { + return { _pimpl->getName(std::move(params)) }; + } + else if constexpr (methods::FolderHas::getName) + { + return { _pimpl->getName() }; + } + else + { + throw std::runtime_error(R"ex(Folder::getName is not implemented)ex"); + } + } + + service::AwaitableScalar getUnreadCount(service::FieldParams&& params) const final + { + if constexpr (methods::FolderHas::getUnreadCountWithParams) + { + return { _pimpl->getUnreadCount(std::move(params)) }; + } + else if constexpr (methods::FolderHas::getUnreadCount) + { + return { _pimpl->getUnreadCount() }; + } + else + { + throw std::runtime_error(R"ex(Folder::getUnreadCount is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::FolderHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Folder(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Node; + + // Unions which include this type + friend UnionType; + + template + static constexpr bool implements() noexcept + { + return implements::FolderIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Folder(std::shared_ptr pimpl) noexcept + : Folder { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // FOLDEROBJECT_H diff --git a/samples/today/schema/MutationObject.cpp b/samples/today/schema/MutationObject.cpp new file mode 100644 index 00000000..97241a03 --- /dev/null +++ b/samples/today/schema/MutationObject.cpp @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "MutationObject.h" +#include "CompleteTaskPayloadObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Mutation::Mutation(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Mutation::getTypeNames() const noexcept +{ + return { + R"gql(Mutation)gql"sv + }; +} + +service::ResolverMap Mutation::getResolvers() const noexcept +{ + return { + { R"gql(setFloat)gql"sv, [this](service::ResolverParams&& params) { return resolveSetFloat(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(completeTask)gql"sv, [this](service::ResolverParams&& params) { return resolveCompleteTask(std::move(params)); } } + }; +} + +void Mutation::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Mutation::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Mutation::resolveCompleteTask(service::ResolverParams&& params) const +{ + auto argInput = service::ModifiedArgument::require("input", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->applyCompleteTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argInput)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Mutation::resolveSetFloat(service::ResolverParams&& params) const +{ + auto argValue = service::ModifiedArgument::require("value", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->applySetFloat(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argValue)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Mutation::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Mutation)gql" }, std::move(params)); +} + +} // namespace object + +void AddMutationDetails(const std::shared_ptr& typeMutation, const std::shared_ptr& schema) +{ + typeMutation->AddFields({ + schema::Field::Make(R"gql(completeTask)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(CompleteTaskPayload)gql"sv)), { + schema::InputValue::Make(R"gql(input)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(CompleteTaskInput)gql"sv)), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(setFloat)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Float)gql"sv)), { + schema::InputValue::Make(R"gql(value)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Float)gql"sv)), R"gql()gql"sv) + }) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/MutationObject.h b/samples/today/schema/MutationObject.h new file mode 100644 index 00000000..8ef746d8 --- /dev/null +++ b/samples/today/schema/MutationObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef MUTATIONOBJECT_H +#define MUTATIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::MutationHas { + +template +concept applyCompleteTaskWithParams = requires (TImpl impl, service::FieldParams params, CompleteTaskInput inputArg) +{ + { service::AwaitableObject> { impl.applyCompleteTask(std::move(params), std::move(inputArg)) } }; +}; + +template +concept applyCompleteTask = requires (TImpl impl, CompleteTaskInput inputArg) +{ + { service::AwaitableObject> { impl.applyCompleteTask(std::move(inputArg)) } }; +}; + +template +concept applySetFloatWithParams = requires (TImpl impl, service::FieldParams params, double valueArg) +{ + { service::AwaitableScalar { impl.applySetFloat(std::move(params), std::move(valueArg)) } }; +}; + +template +concept applySetFloat = requires (TImpl impl, double valueArg) +{ + { service::AwaitableScalar { impl.applySetFloat(std::move(valueArg)) } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::MutationHas + +class Mutation + : public service::Object +{ +private: + service::AwaitableResolver resolveCompleteTask(service::ResolverParams&& params) const; + service::AwaitableResolver resolveSetFloat(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> applyCompleteTask(service::FieldParams&& params, CompleteTaskInput&& inputArg) const = 0; + virtual service::AwaitableScalar applySetFloat(service::FieldParams&& params, double&& valueArg) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> applyCompleteTask(service::FieldParams&& params, CompleteTaskInput&& inputArg) const final + { + if constexpr (methods::MutationHas::applyCompleteTaskWithParams) + { + return { _pimpl->applyCompleteTask(std::move(params), std::move(inputArg)) }; + } + else if constexpr (methods::MutationHas::applyCompleteTask) + { + return { _pimpl->applyCompleteTask(std::move(inputArg)) }; + } + else + { + throw std::runtime_error(R"ex(Mutation::applyCompleteTask is not implemented)ex"); + } + } + + service::AwaitableScalar applySetFloat(service::FieldParams&& params, double&& valueArg) const final + { + if constexpr (methods::MutationHas::applySetFloatWithParams) + { + return { _pimpl->applySetFloat(std::move(params), std::move(valueArg)) }; + } + else if constexpr (methods::MutationHas::applySetFloat) + { + return { _pimpl->applySetFloat(std::move(valueArg)) }; + } + else + { + throw std::runtime_error(R"ex(Mutation::applySetFloat is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MutationHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MutationHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Mutation(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Mutation(std::shared_ptr pimpl) noexcept + : Mutation { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // MUTATIONOBJECT_H diff --git a/samples/today/schema/NestedTypeObject.cpp b/samples/today/schema/NestedTypeObject.cpp new file mode 100644 index 00000000..c22c6cb5 --- /dev/null +++ b/samples/today/schema/NestedTypeObject.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "NestedTypeObject.h" +#include "NestedTypeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +NestedType::NestedType(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames NestedType::getTypeNames() const noexcept +{ + return { + R"gql(NestedType)gql"sv + }; +} + +service::ResolverMap NestedType::getResolvers() const noexcept +{ + return { + { R"gql(depth)gql"sv, [this](service::ResolverParams&& params) { return resolveDepth(std::move(params)); } }, + { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void NestedType::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void NestedType::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver NestedType::resolveDepth(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getDepth(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver NestedType::resolveNested(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver NestedType::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(NestedType)gql" }, std::move(params)); +} + +} // namespace object + +void AddNestedTypeDetails(const std::shared_ptr& typeNestedType, const std::shared_ptr& schema) +{ + typeNestedType->AddFields({ + schema::Field::Make(R"gql(depth)gql"sv, R"md(Depth of the nested element)md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv))), + schema::Field::Make(R"gql(nested)gql"sv, R"md(Link to the next level)md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(NestedType)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/NestedTypeObject.h b/samples/today/schema/NestedTypeObject.h new file mode 100644 index 00000000..a2f0e22f --- /dev/null +++ b/samples/today/schema/NestedTypeObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef NESTEDTYPEOBJECT_H +#define NESTEDTYPEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::NestedTypeHas { + +template +concept getDepthWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getDepth(std::move(params)) } }; +}; + +template +concept getDepth = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getDepth() } }; +}; + +template +concept getNestedWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNested(std::move(params)) } }; +}; + +template +concept getNested = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNested() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::NestedTypeHas + +class NestedType + : public service::Object +{ +private: + service::AwaitableResolver resolveDepth(service::ResolverParams&& params) const; + service::AwaitableResolver resolveNested(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getDepth(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject> getNested(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getDepth(service::FieldParams&& params) const final + { + if constexpr (methods::NestedTypeHas::getDepthWithParams) + { + return { _pimpl->getDepth(std::move(params)) }; + } + else if constexpr (methods::NestedTypeHas::getDepth) + { + return { _pimpl->getDepth() }; + } + else + { + throw std::runtime_error(R"ex(NestedType::getDepth is not implemented)ex"); + } + } + + service::AwaitableObject> getNested(service::FieldParams&& params) const final + { + if constexpr (methods::NestedTypeHas::getNestedWithParams) + { + return { _pimpl->getNested(std::move(params)) }; + } + else if constexpr (methods::NestedTypeHas::getNested) + { + return { _pimpl->getNested() }; + } + else + { + throw std::runtime_error(R"ex(NestedType::getNested is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::NestedTypeHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::NestedTypeHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + NestedType(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + NestedType(std::shared_ptr pimpl) noexcept + : NestedType { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // NESTEDTYPEOBJECT_H diff --git a/samples/today/schema/NodeObject.cpp b/samples/today/schema/NodeObject.cpp new file mode 100644 index 00000000..93d80e05 --- /dev/null +++ b/samples/today/schema/NodeObject.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "NodeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Node::Node(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void Node::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Node::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddNodeDetails(const std::shared_ptr& typeNode, const std::shared_ptr& schema) +{ + typeNode->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/NodeObject.h b/samples/today/schema/NodeObject.h new file mode 100644 index 00000000..af1a537b --- /dev/null +++ b/samples/today/schema/NodeObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef NODEOBJECT_H +#define NODEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class Node + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + Node(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Node(std::shared_ptr pimpl) noexcept + : Node { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "Node is not implemented"); + } +}; + +} // namespace graphql::today::object + +#endif // NODEOBJECT_H diff --git a/samples/today/schema/PageInfoObject.cpp b/samples/today/schema/PageInfoObject.cpp new file mode 100644 index 00000000..b271ead9 --- /dev/null +++ b/samples/today/schema/PageInfoObject.cpp @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "PageInfoObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +PageInfo::PageInfo(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames PageInfo::getTypeNames() const noexcept +{ + return { + R"gql(PageInfo)gql"sv + }; +} + +service::ResolverMap PageInfo::getResolvers() const noexcept +{ + return { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(hasNextPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasNextPage(std::move(params)); } }, + { R"gql(hasPreviousPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasPreviousPage(std::move(params)); } } + }; +} + +void PageInfo::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void PageInfo::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver PageInfo::resolveHasNextPage(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getHasNextPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getHasPreviousPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver PageInfo::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(PageInfo)gql" }, std::move(params)); +} + +} // namespace object + +void AddPageInfoDetails(const std::shared_ptr& typePageInfo, const std::shared_ptr& schema) +{ + typePageInfo->AddFields({ + schema::Field::Make(R"gql(hasNextPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))), + schema::Field::Make(R"gql(hasPreviousPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/PageInfoObject.h b/samples/today/schema/PageInfoObject.h new file mode 100644 index 00000000..5c46a6c6 --- /dev/null +++ b/samples/today/schema/PageInfoObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef PAGEINFOOBJECT_H +#define PAGEINFOOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::PageInfoHas { + +template +concept getHasNextPageWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getHasNextPage(std::move(params)) } }; +}; + +template +concept getHasNextPage = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getHasNextPage() } }; +}; + +template +concept getHasPreviousPageWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getHasPreviousPage(std::move(params)) } }; +}; + +template +concept getHasPreviousPage = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getHasPreviousPage() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::PageInfoHas + +class PageInfo + : public service::Object +{ +private: + service::AwaitableResolver resolveHasNextPage(service::ResolverParams&& params) const; + service::AwaitableResolver resolveHasPreviousPage(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getHasNextPage(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getHasPreviousPage(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getHasNextPage(service::FieldParams&& params) const final + { + if constexpr (methods::PageInfoHas::getHasNextPageWithParams) + { + return { _pimpl->getHasNextPage(std::move(params)) }; + } + else if constexpr (methods::PageInfoHas::getHasNextPage) + { + return { _pimpl->getHasNextPage() }; + } + else + { + throw std::runtime_error(R"ex(PageInfo::getHasNextPage is not implemented)ex"); + } + } + + service::AwaitableScalar getHasPreviousPage(service::FieldParams&& params) const final + { + if constexpr (methods::PageInfoHas::getHasPreviousPageWithParams) + { + return { _pimpl->getHasPreviousPage(std::move(params)) }; + } + else if constexpr (methods::PageInfoHas::getHasPreviousPage) + { + return { _pimpl->getHasPreviousPage() }; + } + else + { + throw std::runtime_error(R"ex(PageInfo::getHasPreviousPage is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::PageInfoHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::PageInfoHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + PageInfo(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + PageInfo(std::shared_ptr pimpl) noexcept + : PageInfo { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // PAGEINFOOBJECT_H diff --git a/samples/separate/QueryObject.cpp b/samples/today/schema/QueryObject.cpp similarity index 55% rename from samples/separate/QueryObject.cpp rename to samples/today/schema/QueryObject.cpp index 5cfca835..2a374fdf 100644 --- a/samples/separate/QueryObject.cpp +++ b/samples/today/schema/QueryObject.cpp @@ -3,9 +3,22 @@ // WARNING! Do not edit this file manually, your changes will be overwritten. -#include "TodayObjects.h" - -#include "graphqlservice/introspection/Introspection.h" +#include "QueryObject.h" +#include "NodeObject.h" +#include "AppointmentConnectionObject.h" +#include "TaskConnectionObject.h" +#include "FolderConnectionObject.h" +#include "AppointmentObject.h" +#include "TaskObject.h" +#include "FolderObject.h" +#include "NestedTypeObject.h" +#include "ExpensiveObject.h" +#include "UnionTypeObject.h" + +#include "graphqlservice/internal/Introspection.h" + +#include "graphqlservice/introspection/SchemaObject.h" +#include "graphqlservice/introspection/TypeObject.h" #include #include @@ -18,10 +31,23 @@ using namespace std::literals; namespace graphql::today { namespace object { -Query::Query() - : service::Object({ - "Query" - }, { +Query::Query(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _schema { GetSchema() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Query::getTypeNames() const noexcept +{ + return { + R"gql(Query)gql"sv + }; +} + +service::ResolverMap Query::getResolvers() const noexcept +{ + return { { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, { R"gql(tasks)gql"sv, [this](service::ResolverParams&& params) { return resolveTasks(std::move(params)); } }, { R"gql(__type)gql"sv, [this](service::ResolverParams&& params) { return resolve_type(std::move(params)); } }, @@ -37,92 +63,75 @@ Query::Query() { R"gql(unimplemented)gql"sv, [this](service::ResolverParams&& params) { return resolveUnimplemented(std::move(params)); } }, { R"gql(appointmentsById)gql"sv, [this](service::ResolverParams&& params) { return resolveAppointmentsById(std::move(params)); } }, { R"gql(unreadCountsById)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCountsById(std::move(params)); } } - }) - , _schema(GetSchema()) + }; +} + +void Query::beginSelectionSet(const service::SelectionSetParams& params) const { + _pimpl->beginSelectionSet(params); } -service::FieldResult> Query::getNode(service::FieldParams&&, response::IdType&&) const +void Query::endSelectionSet(const service::SelectionSetParams& params) const { - throw std::runtime_error(R"ex(Query::getNode is not implemented)ex"); + _pimpl->endSelectionSet(params); } -std::future Query::resolveNode(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveNode(service::ResolverParams&& params) const { auto argId = service::ModifiedArgument::require("id", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); + auto result = _pimpl->getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); resolverLock.unlock(); - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getAppointments(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getAppointments is not implemented)ex"); + return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Query::resolveAppointments(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveAppointments(service::ResolverParams&& params) const { - auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); auto argBefore = service::ModifiedArgument::require("before", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getAppointments(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + auto result = _pimpl->getAppointments(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult> Query::getTasks(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getTasks is not implemented)ex"); -} - -std::future Query::resolveTasks(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveTasks(service::ResolverParams&& params) const { - auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); auto argBefore = service::ModifiedArgument::require("before", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getTasks(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + auto result = _pimpl->getTasks(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult> Query::getUnreadCounts(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const +service::AwaitableResolver Query::resolveUnreadCounts(service::ResolverParams&& params) const { - throw std::runtime_error(R"ex(Query::getUnreadCounts is not implemented)ex"); -} - -std::future Query::resolveUnreadCounts(service::ResolverParams&& params) -{ - auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); auto argBefore = service::ModifiedArgument::require("before", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCounts(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + auto result = _pimpl->getUnreadCounts(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult>> Query::getAppointmentsById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getAppointmentsById is not implemented)ex"); -} - -std::future Query::resolveAppointmentsById(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveAppointmentsById(service::ResolverParams&& params) const { - const auto defaultArguments = []() + static const auto defaultArguments = []() { response::Value values(response::Type::Map); response::Value entry; @@ -147,180 +156,145 @@ std::future Query::resolveAppointmentsById(service::Res : service::ModifiedArgument::require("ids", defaultArguments)); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getAppointmentsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); + auto result = _pimpl->getAppointmentsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult>> Query::getTasksById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getTasksById is not implemented)ex"); -} - -std::future Query::resolveTasksById(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveTasksById(service::ResolverParams&& params) const { auto argIds = service::ModifiedArgument::require("ids", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getTasksById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); + auto result = _pimpl->getTasksById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult>> Query::getUnreadCountsById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getUnreadCountsById is not implemented)ex"); -} - -std::future Query::resolveUnreadCountsById(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveUnreadCountsById(service::ResolverParams&& params) const { auto argIds = service::ModifiedArgument::require("ids", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCountsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); + auto result = _pimpl->getUnreadCountsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult> Query::getNested(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getNested is not implemented)ex"); -} - -std::future Query::resolveNested(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveNested(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult Query::getUnimplemented(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getUnimplemented is not implemented)ex"); -} - -std::future Query::resolveUnimplemented(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveUnimplemented(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getUnimplemented(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getUnimplemented(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); - return service::ModifiedResult::convert(std::move(result), std::move(params)); + return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult>> Query::getExpensive(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getExpensive is not implemented)ex"); -} - -std::future Query::resolveExpensive(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveExpensive(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getExpensive(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getExpensive(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult Query::getTestTaskState(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getTestTaskState is not implemented)ex"); -} - -std::future Query::resolveTestTaskState(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveTestTaskState(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getTestTaskState(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getTestTaskState(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult>> Query::getAnyType(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getAnyType is not implemented)ex"); -} - -std::future Query::resolveAnyType(service::ResolverParams&& params) +service::AwaitableResolver Query::resolveAnyType(service::ResolverParams&& params) const { auto argIds = service::ModifiedArgument::require("ids", params.arguments); std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getAnyType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); + auto result = _pimpl->getAnyType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); resolverLock.unlock(); - return service::ModifiedResult::convert(std::move(result), std::move(params)); + return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Query::resolve_typename(service::ResolverParams&& params) +service::AwaitableResolver Query::resolve_typename(service::ResolverParams&& params) const { - return service::ModifiedResult::convert(response::StringType{ R"gql(Query)gql" }, std::move(params)); + return service::ModifiedResult::convert(std::string{ R"gql(Query)gql" }, std::move(params)); } -std::future Query::resolve_schema(service::ResolverParams&& params) +service::AwaitableResolver Query::resolve_schema(service::ResolverParams&& params) const { - return service::ModifiedResult::convert(std::static_pointer_cast(std::make_shared(_schema)), std::move(params)); + return service::ModifiedResult::convert(std::static_pointer_cast(std::make_shared(std::make_shared(_schema))), std::move(params)); } -std::future Query::resolve_type(service::ResolverParams&& params) +service::AwaitableResolver Query::resolve_type(service::ResolverParams&& params) const { - auto argName = service::ModifiedArgument::require("name", params.arguments); + auto argName = service::ModifiedArgument::require("name", params.arguments); const auto& baseType = _schema->LookupType(argName); - std::shared_ptr result { baseType ? std::make_shared(baseType) : nullptr }; + std::shared_ptr result { baseType ? std::make_shared(std::make_shared(baseType)) : nullptr }; return service::ModifiedResult::convert(result, std::move(params)); } } // namespace object -void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema) +void AddQueryDetails(const std::shared_ptr& typeQuery, const std::shared_ptr& schema) { typeQuery->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md([Object Identification](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#object-identification))md"sv, std::nullopt, schema->LookupType("Node"), { - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + schema::Field::Make(R"gql(node)gql"sv, R"md([Object Identification](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#object-identification))md"sv, std::nullopt, schema->LookupType(R"gql(Node)gql"sv), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv) }), - schema::Field::Make(R"gql(appointments)gql"sv, R"md(Appointments [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("AppointmentConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + schema::Field::Make(R"gql(appointments)gql"sv, R"md(Appointments [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(AppointmentConnection)gql"sv)), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv) }), - schema::Field::Make(R"gql(tasks)gql"sv, R"md(Tasks [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + schema::Field::Make(R"gql(tasks)gql"sv, R"md(Tasks [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(TaskConnection)gql"sv)), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv) }), - schema::Field::Make(R"gql(unreadCounts)gql"sv, R"md(Folder unread counts [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("FolderConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + schema::Field::Make(R"gql(unreadCounts)gql"sv, R"md(Folder unread counts [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(FolderConnection)gql"sv)), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ItemCursor)gql"sv), R"gql()gql"sv) }), - schema::Field::Make(R"gql(appointmentsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Appointment"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql"sv) + schema::Field::Make(R"gql(appointmentsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Appointment)gql"sv))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql"sv) }), - schema::Field::Make(R"gql(tasksById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Task"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + schema::Field::Make(R"gql(tasksById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Task)gql"sv))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)))), R"gql()gql"sv) }), - schema::Field::Make(R"gql(unreadCountsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Folder"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + schema::Field::Make(R"gql(unreadCountsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Folder)gql"sv))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)))), R"gql()gql"sv) }), - schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))), - schema::Field::Make(R"gql(unimplemented)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(expensive)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Expensive"))))), - schema::Field::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskState"))), - schema::Field::Make(R"gql(anyType)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("UnionType"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(NestedType)gql"sv))), + schema::Field::Make(R"gql(unimplemented)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(expensive)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Expensive)gql"sv))))), + schema::Field::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(TaskState)gql"sv))), + schema::Field::Make(R"gql(anyType)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(UnionType)gql"sv))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)))), R"gql()gql"sv) }) }); } diff --git a/samples/today/schema/QueryObject.h b/samples/today/schema/QueryObject.h new file mode 100644 index 00000000..44c2d420 --- /dev/null +++ b/samples/today/schema/QueryObject.h @@ -0,0 +1,459 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef QUERYOBJECT_H +#define QUERYOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::QueryHas { + +template +concept getNodeWithParams = requires (TImpl impl, service::FieldParams params, response::IdType idArg) +{ + { service::AwaitableObject> { impl.getNode(std::move(params), std::move(idArg)) } }; +}; + +template +concept getNode = requires (TImpl impl, response::IdType idArg) +{ + { service::AwaitableObject> { impl.getNode(std::move(idArg)) } }; +}; + +template +concept getAppointmentsWithParams = requires (TImpl impl, service::FieldParams params, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getAppointments(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getAppointments = requires (TImpl impl, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getAppointments(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getTasksWithParams = requires (TImpl impl, service::FieldParams params, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getTasks(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getTasks = requires (TImpl impl, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getTasks(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getUnreadCountsWithParams = requires (TImpl impl, service::FieldParams params, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getUnreadCounts(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getUnreadCounts = requires (TImpl impl, std::optional firstArg, std::optional afterArg, std::optional lastArg, std::optional beforeArg) +{ + { service::AwaitableObject> { impl.getUnreadCounts(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) } }; +}; + +template +concept getAppointmentsByIdWithParams = requires (TImpl impl, service::FieldParams params, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getAppointmentsById(std::move(params), std::move(idsArg)) } }; +}; + +template +concept getAppointmentsById = requires (TImpl impl, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getAppointmentsById(std::move(idsArg)) } }; +}; + +template +concept getTasksByIdWithParams = requires (TImpl impl, service::FieldParams params, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getTasksById(std::move(params), std::move(idsArg)) } }; +}; + +template +concept getTasksById = requires (TImpl impl, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getTasksById(std::move(idsArg)) } }; +}; + +template +concept getUnreadCountsByIdWithParams = requires (TImpl impl, service::FieldParams params, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getUnreadCountsById(std::move(params), std::move(idsArg)) } }; +}; + +template +concept getUnreadCountsById = requires (TImpl impl, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getUnreadCountsById(std::move(idsArg)) } }; +}; + +template +concept getNestedWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNested(std::move(params)) } }; +}; + +template +concept getNested = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNested() } }; +}; + +template +concept getUnimplementedWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getUnimplemented(std::move(params)) } }; +}; + +template +concept getUnimplemented = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getUnimplemented() } }; +}; + +template +concept getExpensiveWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject>> { impl.getExpensive(std::move(params)) } }; +}; + +template +concept getExpensive = requires (TImpl impl) +{ + { service::AwaitableObject>> { impl.getExpensive() } }; +}; + +template +concept getTestTaskStateWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getTestTaskState(std::move(params)) } }; +}; + +template +concept getTestTaskState = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getTestTaskState() } }; +}; + +template +concept getAnyTypeWithParams = requires (TImpl impl, service::FieldParams params, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getAnyType(std::move(params), std::move(idsArg)) } }; +}; + +template +concept getAnyType = requires (TImpl impl, std::vector idsArg) +{ + { service::AwaitableObject>> { impl.getAnyType(std::move(idsArg)) } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::QueryHas + +class Query + : public service::Object +{ +private: + service::AwaitableResolver resolveNode(service::ResolverParams&& params) const; + service::AwaitableResolver resolveAppointments(service::ResolverParams&& params) const; + service::AwaitableResolver resolveTasks(service::ResolverParams&& params) const; + service::AwaitableResolver resolveUnreadCounts(service::ResolverParams&& params) const; + service::AwaitableResolver resolveAppointmentsById(service::ResolverParams&& params) const; + service::AwaitableResolver resolveTasksById(service::ResolverParams&& params) const; + service::AwaitableResolver resolveUnreadCountsById(service::ResolverParams&& params) const; + service::AwaitableResolver resolveNested(service::ResolverParams&& params) const; + service::AwaitableResolver resolveUnimplemented(service::ResolverParams&& params) const; + service::AwaitableResolver resolveExpensive(service::ResolverParams&& params) const; + service::AwaitableResolver resolveTestTaskState(service::ResolverParams&& params) const; + service::AwaitableResolver resolveAnyType(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + service::AwaitableResolver resolve_schema(service::ResolverParams&& params) const; + service::AwaitableResolver resolve_type(service::ResolverParams&& params) const; + + std::shared_ptr _schema; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getNode(service::FieldParams&& params, response::IdType&& idArg) const = 0; + virtual service::AwaitableObject> getAppointments(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const = 0; + virtual service::AwaitableObject> getTasks(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const = 0; + virtual service::AwaitableObject> getUnreadCounts(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const = 0; + virtual service::AwaitableObject>> getAppointmentsById(service::FieldParams&& params, std::vector&& idsArg) const = 0; + virtual service::AwaitableObject>> getTasksById(service::FieldParams&& params, std::vector&& idsArg) const = 0; + virtual service::AwaitableObject>> getUnreadCountsById(service::FieldParams&& params, std::vector&& idsArg) const = 0; + virtual service::AwaitableObject> getNested(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getUnimplemented(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>> getExpensive(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getTestTaskState(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>> getAnyType(service::FieldParams&& params, std::vector&& idsArg) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getNode(service::FieldParams&& params, response::IdType&& idArg) const final + { + if constexpr (methods::QueryHas::getNodeWithParams) + { + return { _pimpl->getNode(std::move(params), std::move(idArg)) }; + } + else if constexpr (methods::QueryHas::getNode) + { + return { _pimpl->getNode(std::move(idArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getNode is not implemented)ex"); + } + } + + service::AwaitableObject> getAppointments(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const final + { + if constexpr (methods::QueryHas::getAppointmentsWithParams) + { + return { _pimpl->getAppointments(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else if constexpr (methods::QueryHas::getAppointments) + { + return { _pimpl->getAppointments(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getAppointments is not implemented)ex"); + } + } + + service::AwaitableObject> getTasks(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const final + { + if constexpr (methods::QueryHas::getTasksWithParams) + { + return { _pimpl->getTasks(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else if constexpr (methods::QueryHas::getTasks) + { + return { _pimpl->getTasks(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getTasks is not implemented)ex"); + } + } + + service::AwaitableObject> getUnreadCounts(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const final + { + if constexpr (methods::QueryHas::getUnreadCountsWithParams) + { + return { _pimpl->getUnreadCounts(std::move(params), std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else if constexpr (methods::QueryHas::getUnreadCounts) + { + return { _pimpl->getUnreadCounts(std::move(firstArg), std::move(afterArg), std::move(lastArg), std::move(beforeArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getUnreadCounts is not implemented)ex"); + } + } + + service::AwaitableObject>> getAppointmentsById(service::FieldParams&& params, std::vector&& idsArg) const final + { + if constexpr (methods::QueryHas::getAppointmentsByIdWithParams) + { + return { _pimpl->getAppointmentsById(std::move(params), std::move(idsArg)) }; + } + else if constexpr (methods::QueryHas::getAppointmentsById) + { + return { _pimpl->getAppointmentsById(std::move(idsArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getAppointmentsById is not implemented)ex"); + } + } + + service::AwaitableObject>> getTasksById(service::FieldParams&& params, std::vector&& idsArg) const final + { + if constexpr (methods::QueryHas::getTasksByIdWithParams) + { + return { _pimpl->getTasksById(std::move(params), std::move(idsArg)) }; + } + else if constexpr (methods::QueryHas::getTasksById) + { + return { _pimpl->getTasksById(std::move(idsArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getTasksById is not implemented)ex"); + } + } + + service::AwaitableObject>> getUnreadCountsById(service::FieldParams&& params, std::vector&& idsArg) const final + { + if constexpr (methods::QueryHas::getUnreadCountsByIdWithParams) + { + return { _pimpl->getUnreadCountsById(std::move(params), std::move(idsArg)) }; + } + else if constexpr (methods::QueryHas::getUnreadCountsById) + { + return { _pimpl->getUnreadCountsById(std::move(idsArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getUnreadCountsById is not implemented)ex"); + } + } + + service::AwaitableObject> getNested(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getNestedWithParams) + { + return { _pimpl->getNested(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getNested) + { + return { _pimpl->getNested() }; + } + else + { + throw std::runtime_error(R"ex(Query::getNested is not implemented)ex"); + } + } + + service::AwaitableScalar getUnimplemented(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getUnimplementedWithParams) + { + return { _pimpl->getUnimplemented(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getUnimplemented) + { + return { _pimpl->getUnimplemented() }; + } + else + { + throw std::runtime_error(R"ex(Query::getUnimplemented is not implemented)ex"); + } + } + + service::AwaitableObject>> getExpensive(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getExpensiveWithParams) + { + return { _pimpl->getExpensive(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getExpensive) + { + return { _pimpl->getExpensive() }; + } + else + { + throw std::runtime_error(R"ex(Query::getExpensive is not implemented)ex"); + } + } + + service::AwaitableScalar getTestTaskState(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getTestTaskStateWithParams) + { + return { _pimpl->getTestTaskState(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getTestTaskState) + { + return { _pimpl->getTestTaskState() }; + } + else + { + throw std::runtime_error(R"ex(Query::getTestTaskState is not implemented)ex"); + } + } + + service::AwaitableObject>> getAnyType(service::FieldParams&& params, std::vector&& idsArg) const final + { + if constexpr (methods::QueryHas::getAnyTypeWithParams) + { + return { _pimpl->getAnyType(std::move(params), std::move(idsArg)) }; + } + else if constexpr (methods::QueryHas::getAnyType) + { + return { _pimpl->getAnyType(std::move(idsArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getAnyType is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::QueryHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::QueryHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Query(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Query(std::shared_ptr pimpl) noexcept + : Query { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // QUERYOBJECT_H diff --git a/samples/today/schema/SubscriptionObject.cpp b/samples/today/schema/SubscriptionObject.cpp new file mode 100644 index 00000000..00d348ce --- /dev/null +++ b/samples/today/schema/SubscriptionObject.cpp @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "SubscriptionObject.h" +#include "AppointmentObject.h" +#include "NodeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Subscription::Subscription(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Subscription::getTypeNames() const noexcept +{ + return { + R"gql(Subscription)gql"sv + }; +} + +service::ResolverMap Subscription::getResolvers() const noexcept +{ + return { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(nodeChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNodeChange(std::move(params)); } }, + { R"gql(nextAppointmentChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNextAppointmentChange(std::move(params)); } } + }; +} + +void Subscription::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Subscription::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNextAppointmentChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Subscription::resolveNodeChange(service::ResolverParams&& params) const +{ + auto argId = service::ModifiedArgument::require("id", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNodeChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Subscription::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Subscription)gql" }, std::move(params)); +} + +} // namespace object + +void AddSubscriptionDetails(const std::shared_ptr& typeSubscription, const std::shared_ptr& schema) +{ + typeSubscription->AddFields({ + schema::Field::Make(R"gql(nextAppointmentChange)gql"sv, R"md()md"sv, std::make_optional(R"md(Need to deprecate a [field](https://spec.graphql.org/October2021/#sec-Schema-Introspection.Deprecation))md"sv), schema->LookupType(R"gql(Appointment)gql"sv)), + schema::Field::Make(R"gql(nodeChange)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Node)gql"sv)), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv) + }) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/SubscriptionObject.h b/samples/today/schema/SubscriptionObject.h new file mode 100644 index 00000000..4729e852 --- /dev/null +++ b/samples/today/schema/SubscriptionObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef SUBSCRIPTIONOBJECT_H +#define SUBSCRIPTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::SubscriptionHas { + +template +concept getNextAppointmentChangeWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNextAppointmentChange(std::move(params)) } }; +}; + +template +concept getNextAppointmentChange = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNextAppointmentChange() } }; +}; + +template +concept getNodeChangeWithParams = requires (TImpl impl, service::FieldParams params, response::IdType idArg) +{ + { service::AwaitableObject> { impl.getNodeChange(std::move(params), std::move(idArg)) } }; +}; + +template +concept getNodeChange = requires (TImpl impl, response::IdType idArg) +{ + { service::AwaitableObject> { impl.getNodeChange(std::move(idArg)) } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::SubscriptionHas + +class Subscription + : public service::Object +{ +private: + service::AwaitableResolver resolveNextAppointmentChange(service::ResolverParams&& params) const; + service::AwaitableResolver resolveNodeChange(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getNextAppointmentChange(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getNextAppointmentChange(service::FieldParams&& params) const final + { + if constexpr (methods::SubscriptionHas::getNextAppointmentChangeWithParams) + { + return { _pimpl->getNextAppointmentChange(std::move(params)) }; + } + else if constexpr (methods::SubscriptionHas::getNextAppointmentChange) + { + return { _pimpl->getNextAppointmentChange() }; + } + else + { + throw std::runtime_error(R"ex(Subscription::getNextAppointmentChange is not implemented)ex"); + } + } + + service::AwaitableObject> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const final + { + if constexpr (methods::SubscriptionHas::getNodeChangeWithParams) + { + return { _pimpl->getNodeChange(std::move(params), std::move(idArg)) }; + } + else if constexpr (methods::SubscriptionHas::getNodeChange) + { + return { _pimpl->getNodeChange(std::move(idArg)) }; + } + else + { + throw std::runtime_error(R"ex(Subscription::getNodeChange is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::SubscriptionHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::SubscriptionHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Subscription(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Subscription(std::shared_ptr pimpl) noexcept + : Subscription { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // SUBSCRIPTIONOBJECT_H diff --git a/samples/today/schema/TaskConnectionObject.cpp b/samples/today/schema/TaskConnectionObject.cpp new file mode 100644 index 00000000..27c0c6b4 --- /dev/null +++ b/samples/today/schema/TaskConnectionObject.cpp @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "TaskConnectionObject.h" +#include "PageInfoObject.h" +#include "TaskEdgeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +TaskConnection::TaskConnection(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames TaskConnection::getTypeNames() const noexcept +{ + return { + R"gql(TaskConnection)gql"sv + }; +} + +service::ResolverMap TaskConnection::getResolvers() const noexcept +{ + return { + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void TaskConnection::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void TaskConnection::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver TaskConnection::resolvePageInfo(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver TaskConnection::resolveEdges(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver TaskConnection::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(TaskConnection)gql" }, std::move(params)); +} + +} // namespace object + +void AddTaskConnectionDetails(const std::shared_ptr& typeTaskConnection, const std::shared_ptr& schema) +{ + typeTaskConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PageInfo)gql"sv))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(TaskEdge)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/TaskConnectionObject.h b/samples/today/schema/TaskConnectionObject.h new file mode 100644 index 00000000..b926979d --- /dev/null +++ b/samples/today/schema/TaskConnectionObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef TASKCONNECTIONOBJECT_H +#define TASKCONNECTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::TaskConnectionHas { + +template +concept getPageInfoWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getPageInfo(std::move(params)) } }; +}; + +template +concept getPageInfo = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getPageInfo() } }; +}; + +template +concept getEdgesWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject>>> { impl.getEdges(std::move(params)) } }; +}; + +template +concept getEdges = requires (TImpl impl) +{ + { service::AwaitableObject>>> { impl.getEdges() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::TaskConnectionHas + +class TaskConnection + : public service::Object +{ +private: + service::AwaitableResolver resolvePageInfo(service::ResolverParams&& params) const; + service::AwaitableResolver resolveEdges(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getPageInfo(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>>> getEdges(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getPageInfo(service::FieldParams&& params) const final + { + if constexpr (methods::TaskConnectionHas::getPageInfoWithParams) + { + return { _pimpl->getPageInfo(std::move(params)) }; + } + else if constexpr (methods::TaskConnectionHas::getPageInfo) + { + return { _pimpl->getPageInfo() }; + } + else + { + throw std::runtime_error(R"ex(TaskConnection::getPageInfo is not implemented)ex"); + } + } + + service::AwaitableObject>>> getEdges(service::FieldParams&& params) const final + { + if constexpr (methods::TaskConnectionHas::getEdgesWithParams) + { + return { _pimpl->getEdges(std::move(params)) }; + } + else if constexpr (methods::TaskConnectionHas::getEdges) + { + return { _pimpl->getEdges() }; + } + else + { + throw std::runtime_error(R"ex(TaskConnection::getEdges is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskConnectionHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskConnectionHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + TaskConnection(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + TaskConnection(std::shared_ptr pimpl) noexcept + : TaskConnection { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // TASKCONNECTIONOBJECT_H diff --git a/samples/today/schema/TaskEdgeObject.cpp b/samples/today/schema/TaskEdgeObject.cpp new file mode 100644 index 00000000..6780e548 --- /dev/null +++ b/samples/today/schema/TaskEdgeObject.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "TaskEdgeObject.h" +#include "TaskObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +TaskEdge::TaskEdge(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames TaskEdge::getTypeNames() const noexcept +{ + return { + R"gql(TaskEdge)gql"sv + }; +} + +service::ResolverMap TaskEdge::getResolvers() const noexcept +{ + return { + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void TaskEdge::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void TaskEdge::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver TaskEdge::resolveNode(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver TaskEdge::resolveCursor(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver TaskEdge::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(TaskEdge)gql" }, std::move(params)); +} + +} // namespace object + +void AddTaskEdgeDetails(const std::shared_ptr& typeTaskEdge, const std::shared_ptr& schema) +{ + typeTaskEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Task)gql"sv)), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ItemCursor)gql"sv))) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/TaskEdgeObject.h b/samples/today/schema/TaskEdgeObject.h new file mode 100644 index 00000000..7a934280 --- /dev/null +++ b/samples/today/schema/TaskEdgeObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef TASKEDGEOBJECT_H +#define TASKEDGEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace methods::TaskEdgeHas { + +template +concept getNodeWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNode(std::move(params)) } }; +}; + +template +concept getNode = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNode() } }; +}; + +template +concept getCursorWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getCursor(std::move(params)) } }; +}; + +template +concept getCursor = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getCursor() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::TaskEdgeHas + +class TaskEdge + : public service::Object +{ +private: + service::AwaitableResolver resolveNode(service::ResolverParams&& params) const; + service::AwaitableResolver resolveCursor(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getNode(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getCursor(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getNode(service::FieldParams&& params) const final + { + if constexpr (methods::TaskEdgeHas::getNodeWithParams) + { + return { _pimpl->getNode(std::move(params)) }; + } + else if constexpr (methods::TaskEdgeHas::getNode) + { + return { _pimpl->getNode() }; + } + else + { + throw std::runtime_error(R"ex(TaskEdge::getNode is not implemented)ex"); + } + } + + service::AwaitableScalar getCursor(service::FieldParams&& params) const final + { + if constexpr (methods::TaskEdgeHas::getCursorWithParams) + { + return { _pimpl->getCursor(std::move(params)) }; + } + else if constexpr (methods::TaskEdgeHas::getCursor) + { + return { _pimpl->getCursor() }; + } + else + { + throw std::runtime_error(R"ex(TaskEdge::getCursor is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskEdgeHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskEdgeHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + TaskEdge(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + TaskEdge(std::shared_ptr pimpl) noexcept + : TaskEdge { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // TASKEDGEOBJECT_H diff --git a/samples/separate_nointrospection/TaskObject.cpp b/samples/today/schema/TaskObject.cpp similarity index 50% rename from samples/separate_nointrospection/TaskObject.cpp rename to samples/today/schema/TaskObject.cpp index 06e9492d..578ea5bf 100644 --- a/samples/separate_nointrospection/TaskObject.cpp +++ b/samples/today/schema/TaskObject.cpp @@ -3,9 +3,11 @@ // WARNING! Do not edit this file manually, your changes will be overwritten. -#include "TodayObjects.h" +#include "TaskObject.h" -#include "graphqlservice/introspection/Introspection.h" +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" #include #include @@ -18,81 +20,87 @@ using namespace std::literals; namespace graphql::today { namespace object { -Task::Task() - : service::Object({ - "Node", - "UnionType", - "Task" - }, { +Task::Task(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Task::getTypeNames() const noexcept +{ + return { + R"gql(Node)gql"sv, + R"gql(UnionType)gql"sv, + R"gql(Task)gql"sv + }; +} + +service::ResolverMap Task::getResolvers() const noexcept +{ + return { { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, { R"gql(title)gql"sv, [this](service::ResolverParams&& params) { return resolveTitle(std::move(params)); } }, { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, { R"gql(isComplete)gql"sv, [this](service::ResolverParams&& params) { return resolveIsComplete(std::move(params)); } } - }) + }; +} + +void Task::beginSelectionSet(const service::SelectionSetParams& params) const { + _pimpl->beginSelectionSet(params); } -service::FieldResult Task::getId(service::FieldParams&&) const +void Task::endSelectionSet(const service::SelectionSetParams& params) const { - throw std::runtime_error(R"ex(Task::getId is not implemented)ex"); + _pimpl->endSelectionSet(params); } -std::future Task::resolveId(service::ResolverParams&& params) +service::AwaitableResolver Task::resolveId(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); return service::ModifiedResult::convert(std::move(result), std::move(params)); } -service::FieldResult> Task::getTitle(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Task::getTitle is not implemented)ex"); -} - -std::future Task::resolveTitle(service::ResolverParams&& params) +service::AwaitableResolver Task::resolveTitle(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getTitle(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getTitle(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Task::getIsComplete(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Task::getIsComplete is not implemented)ex"); + return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Task::resolveIsComplete(service::ResolverParams&& params) +service::AwaitableResolver Task::resolveIsComplete(service::ResolverParams&& params) const { std::unique_lock resolverLock(_resolverMutex); auto directives = std::move(params.fieldDirectives); - auto result = getIsComplete(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + auto result = _pimpl->getIsComplete(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); resolverLock.unlock(); - return service::ModifiedResult::convert(std::move(result), std::move(params)); + return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Task::resolve_typename(service::ResolverParams&& params) +service::AwaitableResolver Task::resolve_typename(service::ResolverParams&& params) const { - return service::ModifiedResult::convert(response::StringType{ R"gql(Task)gql" }, std::move(params)); + return service::ModifiedResult::convert(std::string{ R"gql(Task)gql" }, std::move(params)); } } // namespace object -void AddTaskDetails(std::shared_ptr typeTask, const std::shared_ptr& schema) +void AddTaskDetails(const std::shared_ptr& typeTask, const std::shared_ptr& schema) { typeTask->AddInterfaces({ std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) }); typeTask->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(title)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(isComplete)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))), + schema::Field::Make(R"gql(title)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(isComplete)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))) }); } diff --git a/samples/today/schema/TaskObject.h b/samples/today/schema/TaskObject.h new file mode 100644 index 00000000..b0746bd8 --- /dev/null +++ b/samples/today/schema/TaskObject.h @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef TASKOBJECT_H +#define TASKOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { +namespace implements { + +template +concept TaskIs = std::is_same_v || std::is_same_v; + +} // namespace implements + +namespace methods::TaskHas { + +template +concept getIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getId(std::move(params)) } }; +}; + +template +concept getId = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getId() } }; +}; + +template +concept getTitleWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getTitle(std::move(params)) } }; +}; + +template +concept getTitle = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getTitle() } }; +}; + +template +concept getIsCompleteWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getIsComplete(std::move(params)) } }; +}; + +template +concept getIsComplete = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getIsComplete() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::TaskHas + +class Task + : public service::Object +{ +private: + service::AwaitableResolver resolveId(service::ResolverParams&& params) const; + service::AwaitableResolver resolveTitle(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIsComplete(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getId(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getTitle(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getIsComplete(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getId(service::FieldParams&& params) const final + { + if constexpr (methods::TaskHas::getIdWithParams) + { + return { _pimpl->getId(std::move(params)) }; + } + else if constexpr (methods::TaskHas::getId) + { + return { _pimpl->getId() }; + } + else + { + throw std::runtime_error(R"ex(Task::getId is not implemented)ex"); + } + } + + service::AwaitableScalar> getTitle(service::FieldParams&& params) const final + { + if constexpr (methods::TaskHas::getTitleWithParams) + { + return { _pimpl->getTitle(std::move(params)) }; + } + else if constexpr (methods::TaskHas::getTitle) + { + return { _pimpl->getTitle() }; + } + else + { + throw std::runtime_error(R"ex(Task::getTitle is not implemented)ex"); + } + } + + service::AwaitableScalar getIsComplete(service::FieldParams&& params) const final + { + if constexpr (methods::TaskHas::getIsCompleteWithParams) + { + return { _pimpl->getIsComplete(std::move(params)) }; + } + else if constexpr (methods::TaskHas::getIsComplete) + { + return { _pimpl->getIsComplete() }; + } + else + { + throw std::runtime_error(R"ex(Task::getIsComplete is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::TaskHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Task(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Node; + + // Unions which include this type + friend UnionType; + + template + static constexpr bool implements() noexcept + { + return implements::TaskIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Task(std::shared_ptr pimpl) noexcept + : Task { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::today::object + +#endif // TASKOBJECT_H diff --git a/samples/separate/TodaySchema.cpp b/samples/today/schema/TodaySchema.cpp similarity index 77% rename from samples/separate/TodaySchema.cpp rename to samples/today/schema/TodaySchema.cpp index 07b69b6f..994ea7d6 100644 --- a/samples/separate/TodaySchema.cpp +++ b/samples/today/schema/TodaySchema.cpp @@ -3,9 +3,13 @@ // WARNING! Do not edit this file manually, your changes will be overwritten. -#include "TodayObjects.h" +#include "QueryObject.h" +#include "MutationObject.h" +#include "SubscriptionObject.h" -#include "graphqlservice/introspection/Introspection.h" +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" #include #include @@ -22,10 +26,10 @@ namespace graphql { namespace service { static const std::array s_namesTaskState = { - "New"sv, - "Started"sv, - "Complete"sv, - "Unassigned"sv + R"gql(New)gql"sv, + R"gql(Started)gql"sv, + R"gql(Complete)gql"sv, + R"gql(Unassigned)gql"sv }; template <> @@ -33,33 +37,49 @@ today::TaskState ModifiedArgument::convert(const response::Val { if (!value.maybe_enum()) { - throw service::schema_exception { { "not a valid TaskState value" } }; + throw service::schema_exception { { R"ex(not a valid TaskState value)ex" } }; } - const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.get()); + const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.get()); if (itr == s_namesTaskState.cend()) { - throw service::schema_exception { { "not a valid TaskState value" } }; + throw service::schema_exception { { R"ex(not a valid TaskState value)ex" } }; } return static_cast(itr - s_namesTaskState.cbegin()); } template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) +service::AwaitableResolver ModifiedResult::convert(service::AwaitableScalar result, ResolverParams params) { return resolve(std::move(result), std::move(params), [](today::TaskState value, const ResolverParams&) { response::Value result(response::Type::EnumValue); - result.set(response::StringType { s_namesTaskState[static_cast(value)] }); + result.set(std::string { s_namesTaskState[static_cast(value)] }); return result; }); } +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid TaskState value)ex" } }; + } + + const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.get()); + + if (itr == s_namesTaskState.cend()) + { + throw service::schema_exception { { R"ex(not a valid TaskState value)ex" } }; + } +} + template <> today::CompleteTaskInput ModifiedArgument::convert(const response::Value& value) { @@ -76,11 +96,11 @@ today::CompleteTaskInput ModifiedArgument::convert(con auto valueId = service::ModifiedArgument::require("id", value); auto valueTestTaskState = service::ModifiedArgument::require("testTaskState", value); - auto pairIsComplete = service::ModifiedArgument::find("isComplete", value); + auto pairIsComplete = service::ModifiedArgument::find("isComplete", value); auto valueIsComplete = (pairIsComplete.second ? std::move(pairIsComplete.first) - : service::ModifiedArgument::require("isComplete", defaultValue)); - auto valueClientMutationId = service::ModifiedArgument::require("clientMutationId", value); + : service::ModifiedArgument::require("isComplete", defaultValue)); + auto valueClientMutationId = service::ModifiedArgument::require("clientMutationId", value); return { std::move(valueId), @@ -154,8 +174,8 @@ Operations::Operations(std::shared_ptr query, std::shared_ptr& schema) { - schema->AddType(R"gql(ItemCursor)gql"sv, schema::ScalarType::Make(R"gql(ItemCursor)gql"sv, R"md()md")); - schema->AddType(R"gql(DateTime)gql"sv, schema::ScalarType::Make(R"gql(DateTime)gql"sv, R"md()md")); + schema->AddType(R"gql(ItemCursor)gql"sv, schema::ScalarType::Make(R"gql(ItemCursor)gql"sv, R"md()md", R"url()url"sv)); + schema->AddType(R"gql(DateTime)gql"sv, schema::ScalarType::Make(R"gql(DateTime)gql"sv, R"md()md", R"url(https://en.wikipedia.org/wiki/ISO_8601)url"sv)); auto typeTaskState = schema::EnumType::Make(R"gql(TaskState)gql"sv, R"md()md"sv); schema->AddType(R"gql(TaskState)gql"sv, typeTaskState); auto typeCompleteTaskInput = schema::InputObjectType::Make(R"gql(CompleteTaskInput)gql"sv, R"md()md"sv); @@ -168,81 +188,78 @@ void AddTypesToSchema(const std::shared_ptr& schema) schema->AddType(R"gql(SecondNestedInput)gql"sv, typeSecondNestedInput); auto typeFirstNestedInput = schema::InputObjectType::Make(R"gql(FirstNestedInput)gql"sv, R"md()md"sv); schema->AddType(R"gql(FirstNestedInput)gql"sv, typeFirstNestedInput); - auto typeUnionType = schema::UnionType::Make(R"gql(UnionType)gql"sv, R"md()md"sv); - schema->AddType(R"gql(UnionType)gql"sv, typeUnionType); auto typeNode = schema::InterfaceType::Make(R"gql(Node)gql"sv, R"md(Node interface for Relay support)md"sv); schema->AddType(R"gql(Node)gql"sv, typeNode); - auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md(Root Query type)md"); + auto typeUnionType = schema::UnionType::Make(R"gql(UnionType)gql"sv, R"md()md"sv); + schema->AddType(R"gql(UnionType)gql"sv, typeUnionType); + auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md(Root Query type)md"sv); schema->AddType(R"gql(Query)gql"sv, typeQuery); - auto typePageInfo = schema::ObjectType::Make(R"gql(PageInfo)gql"sv, R"md()md"); + auto typePageInfo = schema::ObjectType::Make(R"gql(PageInfo)gql"sv, R"md()md"sv); schema->AddType(R"gql(PageInfo)gql"sv, typePageInfo); - auto typeAppointmentEdge = schema::ObjectType::Make(R"gql(AppointmentEdge)gql"sv, R"md()md"); + auto typeAppointmentEdge = schema::ObjectType::Make(R"gql(AppointmentEdge)gql"sv, R"md()md"sv); schema->AddType(R"gql(AppointmentEdge)gql"sv, typeAppointmentEdge); - auto typeAppointmentConnection = schema::ObjectType::Make(R"gql(AppointmentConnection)gql"sv, R"md()md"); + auto typeAppointmentConnection = schema::ObjectType::Make(R"gql(AppointmentConnection)gql"sv, R"md()md"sv); schema->AddType(R"gql(AppointmentConnection)gql"sv, typeAppointmentConnection); - auto typeTaskEdge = schema::ObjectType::Make(R"gql(TaskEdge)gql"sv, R"md()md"); + auto typeTaskEdge = schema::ObjectType::Make(R"gql(TaskEdge)gql"sv, R"md()md"sv); schema->AddType(R"gql(TaskEdge)gql"sv, typeTaskEdge); - auto typeTaskConnection = schema::ObjectType::Make(R"gql(TaskConnection)gql"sv, R"md()md"); + auto typeTaskConnection = schema::ObjectType::Make(R"gql(TaskConnection)gql"sv, R"md()md"sv); schema->AddType(R"gql(TaskConnection)gql"sv, typeTaskConnection); - auto typeFolderEdge = schema::ObjectType::Make(R"gql(FolderEdge)gql"sv, R"md()md"); + auto typeFolderEdge = schema::ObjectType::Make(R"gql(FolderEdge)gql"sv, R"md()md"sv); schema->AddType(R"gql(FolderEdge)gql"sv, typeFolderEdge); - auto typeFolderConnection = schema::ObjectType::Make(R"gql(FolderConnection)gql"sv, R"md()md"); + auto typeFolderConnection = schema::ObjectType::Make(R"gql(FolderConnection)gql"sv, R"md()md"sv); schema->AddType(R"gql(FolderConnection)gql"sv, typeFolderConnection); - auto typeCompleteTaskPayload = schema::ObjectType::Make(R"gql(CompleteTaskPayload)gql"sv, R"md()md"); + auto typeCompleteTaskPayload = schema::ObjectType::Make(R"gql(CompleteTaskPayload)gql"sv, R"md()md"sv); schema->AddType(R"gql(CompleteTaskPayload)gql"sv, typeCompleteTaskPayload); - auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"); + auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"sv); schema->AddType(R"gql(Mutation)gql"sv, typeMutation); - auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"); + auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md(Subscription type: + +2nd line... + 3rd line goes here!)md"sv); schema->AddType(R"gql(Subscription)gql"sv, typeSubscription); - auto typeAppointment = schema::ObjectType::Make(R"gql(Appointment)gql"sv, R"md()md"); + auto typeAppointment = schema::ObjectType::Make(R"gql(Appointment)gql"sv, R"md()md"sv); schema->AddType(R"gql(Appointment)gql"sv, typeAppointment); - auto typeTask = schema::ObjectType::Make(R"gql(Task)gql"sv, R"md()md"); + auto typeTask = schema::ObjectType::Make(R"gql(Task)gql"sv, R"md()md"sv); schema->AddType(R"gql(Task)gql"sv, typeTask); - auto typeFolder = schema::ObjectType::Make(R"gql(Folder)gql"sv, R"md()md"); + auto typeFolder = schema::ObjectType::Make(R"gql(Folder)gql"sv, R"md()md"sv); schema->AddType(R"gql(Folder)gql"sv, typeFolder); - auto typeNestedType = schema::ObjectType::Make(R"gql(NestedType)gql"sv, R"md(Infinitely nestable type which can be used with nested fragments to test directive handling)md"); + auto typeNestedType = schema::ObjectType::Make(R"gql(NestedType)gql"sv, R"md(Infinitely nestable type which can be used with nested fragments to test directive handling)md"sv); schema->AddType(R"gql(NestedType)gql"sv, typeNestedType); - auto typeExpensive = schema::ObjectType::Make(R"gql(Expensive)gql"sv, R"md()md"); + auto typeExpensive = schema::ObjectType::Make(R"gql(Expensive)gql"sv, R"md()md"sv); schema->AddType(R"gql(Expensive)gql"sv, typeExpensive); typeTaskState->AddEnumValues({ { service::s_namesTaskState[static_cast(today::TaskState::New)], R"md()md"sv, std::nullopt }, { service::s_namesTaskState[static_cast(today::TaskState::Started)], R"md()md"sv, std::nullopt }, { service::s_namesTaskState[static_cast(today::TaskState::Complete)], R"md()md"sv, std::nullopt }, - { service::s_namesTaskState[static_cast(today::TaskState::Unassigned)], R"md()md"sv, std::make_optional(R"md(Need to deprecate an [enum value](http://spec.graphql.org/June2018/#sec-Deprecation))md"sv) } + { service::s_namesTaskState[static_cast(today::TaskState::Unassigned)], R"md()md"sv, std::make_optional(R"md(Need to deprecate an [enum value](https://spec.graphql.org/October2021/#sec-Schema-Introspection.Deprecation))md"sv) } }); typeCompleteTaskInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, schema->LookupType("TaskState"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(isComplete)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(true)gql"sv), - schema::InputValue::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv), + schema::InputValue::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, schema->LookupType(R"gql(TaskState)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(isComplete)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Boolean)gql"sv), R"gql(true)gql"sv), + schema::InputValue::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql()gql"sv) }); typeThirdNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv) }); typeFourthNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv) }); typeSecondNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ThirdNestedInput")), R"gql()gql"sv) + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv), + schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ThirdNestedInput)gql"sv)), R"gql()gql"sv) }); typeFirstNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(second)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("SecondNestedInput")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ThirdNestedInput")), R"gql()gql"sv) + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv), + schema::InputValue::Make(R"gql(second)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(SecondNestedInput)gql"sv)), R"gql()gql"sv), + schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ThirdNestedInput)gql"sv)), R"gql()gql"sv) }); - typeUnionType->AddPossibleTypes({ - schema->LookupType(R"gql(Appointment)gql"sv), - schema->LookupType(R"gql(Task)gql"sv), - schema->LookupType(R"gql(Folder)gql"sv) - }); + AddNodeDetails(typeNode, schema); - typeNode->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) - }); + AddUnionTypeDetails(typeUnionType, schema); AddQueryDetails(typeQuery, schema); AddPageInfoDetails(typePageInfo, schema); @@ -263,37 +280,35 @@ void AddTypesToSchema(const std::shared_ptr& schema) schema->AddDirective(schema::Directive::Make(R"gql(id)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::FIELD_DEFINITION - })); - schema->AddDirective(schema::Directive::Make(R"gql(subscriptionTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::SUBSCRIPTION - }, { - schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) - })); + }, {}, false)); schema->AddDirective(schema::Directive::Make(R"gql(queryTag)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::QUERY }, { - schema::InputValue::Make(R"gql(query)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); + schema::InputValue::Make(R"gql(query)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }, false)); schema->AddDirective(schema::Directive::Make(R"gql(fieldTag)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::FIELD }, { - schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); + schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }, false)); schema->AddDirective(schema::Directive::Make(R"gql(fragmentDefinitionTag)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::FRAGMENT_DEFINITION }, { - schema::InputValue::Make(R"gql(fragmentDefinition)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); + schema::InputValue::Make(R"gql(fragmentDefinition)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }, false)); schema->AddDirective(schema::Directive::Make(R"gql(fragmentSpreadTag)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::FRAGMENT_SPREAD }, { - schema::InputValue::Make(R"gql(fragmentSpread)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); + schema::InputValue::Make(R"gql(fragmentSpread)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }, false)); schema->AddDirective(schema::Directive::Make(R"gql(inlineFragmentTag)gql"sv, R"md()md"sv, { introspection::DirectiveLocation::INLINE_FRAGMENT }, { - schema::InputValue::Make(R"gql(inlineFragment)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); + schema::InputValue::Make(R"gql(inlineFragment)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }, false)); + schema->AddDirective(schema::Directive::Make(R"gql(repeatableOnField)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD + }, {}, true)); schema->AddQueryType(typeQuery); schema->AddMutationType(typeMutation); @@ -307,7 +322,7 @@ std::shared_ptr GetSchema() if (!schema) { - schema = std::make_shared(false); + schema = std::make_shared(false, R"md(Test Schema based on a dashboard showing daily appointments, tasks, and email folders with unread counts.)md"sv); introspection::AddTypesToSchema(schema); AddTypesToSchema(schema); s_wpSchema = schema; diff --git a/samples/today/schema/TodaySchema.h b/samples/today/schema/TodaySchema.h new file mode 100644 index 00000000..bb0834b2 --- /dev/null +++ b/samples/today/schema/TodaySchema.h @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef TODAYSCHEMA_H +#define TODAYSCHEMA_H + +#include "graphqlservice/internal/Schema.h" + +// Check if the library version is compatible with schemagen 4.0.0 +static_assert(graphql::internal::MajorVersion == 4, "regenerate with schemagen: major version mismatch"); +static_assert(graphql::internal::MinorVersion == 0, "regenerate with schemagen: minor version mismatch"); + +#include +#include +#include + +namespace graphql { +namespace today { + +enum class TaskState +{ + New, + Started, + Complete, + Unassigned +}; + +struct CompleteTaskInput +{ + response::IdType id {}; + std::optional testTaskState {}; + std::optional isComplete {}; + std::optional clientMutationId {}; +}; + +struct ThirdNestedInput +{ + response::IdType id {}; +}; + +struct FourthNestedInput +{ + response::IdType id {}; +}; + +struct SecondNestedInput +{ + response::IdType id {}; + ThirdNestedInput third {}; +}; + +struct FirstNestedInput +{ + response::IdType id {}; + SecondNestedInput second {}; + ThirdNestedInput third {}; +}; + +namespace object { + +class Node; + +class UnionType; + +class Query; +class PageInfo; +class AppointmentEdge; +class AppointmentConnection; +class TaskEdge; +class TaskConnection; +class FolderEdge; +class FolderConnection; +class CompleteTaskPayload; +class Mutation; +class Subscription; +class Appointment; +class Task; +class Folder; +class NestedType; +class Expensive; + +} // namespace object + +class Operations + : public service::Request +{ +public: + explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription); + + template + explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription) + : Operations { std::make_shared(std::move(query)), std::make_shared(std::move(mutation)), std::make_shared(std::move(subscription)) } + { + } + +private: + std::shared_ptr _query; + std::shared_ptr _mutation; + std::shared_ptr _subscription; +}; + +void AddNodeDetails(const std::shared_ptr& typeNode, const std::shared_ptr& schema); + +void AddUnionTypeDetails(const std::shared_ptr& typeUnionType, const std::shared_ptr& schema); + +void AddQueryDetails(const std::shared_ptr& typeQuery, const std::shared_ptr& schema); +void AddPageInfoDetails(const std::shared_ptr& typePageInfo, const std::shared_ptr& schema); +void AddAppointmentEdgeDetails(const std::shared_ptr& typeAppointmentEdge, const std::shared_ptr& schema); +void AddAppointmentConnectionDetails(const std::shared_ptr& typeAppointmentConnection, const std::shared_ptr& schema); +void AddTaskEdgeDetails(const std::shared_ptr& typeTaskEdge, const std::shared_ptr& schema); +void AddTaskConnectionDetails(const std::shared_ptr& typeTaskConnection, const std::shared_ptr& schema); +void AddFolderEdgeDetails(const std::shared_ptr& typeFolderEdge, const std::shared_ptr& schema); +void AddFolderConnectionDetails(const std::shared_ptr& typeFolderConnection, const std::shared_ptr& schema); +void AddCompleteTaskPayloadDetails(const std::shared_ptr& typeCompleteTaskPayload, const std::shared_ptr& schema); +void AddMutationDetails(const std::shared_ptr& typeMutation, const std::shared_ptr& schema); +void AddSubscriptionDetails(const std::shared_ptr& typeSubscription, const std::shared_ptr& schema); +void AddAppointmentDetails(const std::shared_ptr& typeAppointment, const std::shared_ptr& schema); +void AddTaskDetails(const std::shared_ptr& typeTask, const std::shared_ptr& schema); +void AddFolderDetails(const std::shared_ptr& typeFolder, const std::shared_ptr& schema); +void AddNestedTypeDetails(const std::shared_ptr& typeNestedType, const std::shared_ptr& schema); +void AddExpensiveDetails(const std::shared_ptr& typeExpensive, const std::shared_ptr& schema); + +std::shared_ptr GetSchema(); + +} // namespace today +} // namespace graphql + +#endif // TODAYSCHEMA_H diff --git a/samples/today/schema/UnionTypeObject.cpp b/samples/today/schema/UnionTypeObject.cpp new file mode 100644 index 00000000..7955b900 --- /dev/null +++ b/samples/today/schema/UnionTypeObject.cpp @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "UnionTypeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +UnionType::UnionType(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void UnionType::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void UnionType::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddUnionTypeDetails(const std::shared_ptr& typeUnionType, const std::shared_ptr& schema) +{ + typeUnionType->AddPossibleTypes({ + schema->LookupType(R"gql(Appointment)gql"sv), + schema->LookupType(R"gql(Task)gql"sv), + schema->LookupType(R"gql(Folder)gql"sv) + }); +} + +} // namespace graphql::today diff --git a/samples/today/schema/UnionTypeObject.h b/samples/today/schema/UnionTypeObject.h new file mode 100644 index 00000000..4e1ec759 --- /dev/null +++ b/samples/today/schema/UnionTypeObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef UNIONTYPEOBJECT_H +#define UNIONTYPEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class UnionType + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + UnionType(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + UnionType(std::shared_ptr pimpl) noexcept + : UnionType { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "UnionType is not implemented"); + } +}; + +} // namespace graphql::today::object + +#endif // UNIONTYPEOBJECT_H diff --git a/samples/separate/today_schema_files b/samples/today/schema/today_schema_files similarity index 91% rename from samples/separate/today_schema_files rename to samples/today/schema/today_schema_files index f1fb1229..a9ed9ecf 100644 --- a/samples/separate/today_schema_files +++ b/samples/today/schema/today_schema_files @@ -1,4 +1,6 @@ TodaySchema.cpp +NodeObject.cpp +UnionTypeObject.cpp QueryObject.cpp PageInfoObject.cpp AppointmentEdgeObject.cpp diff --git a/samples/unified/TodaySchema.cpp b/samples/unified/TodaySchema.cpp deleted file mode 100644 index 97858c7a..00000000 --- a/samples/unified/TodaySchema.cpp +++ /dev/null @@ -1,1450 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodaySchema.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql { -namespace service { - -static const std::array s_namesTaskState = { - "New"sv, - "Started"sv, - "Complete"sv, - "Unassigned"sv -}; - -template <> -today::TaskState ModifiedArgument::convert(const response::Value& value) -{ - if (!value.maybe_enum()) - { - throw service::schema_exception { { "not a valid TaskState value" } }; - } - - const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.get()); - - if (itr == s_namesTaskState.cend()) - { - throw service::schema_exception { { "not a valid TaskState value" } }; - } - - return static_cast(itr - s_namesTaskState.cbegin()); -} - -template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) -{ - return resolve(std::move(result), std::move(params), - [](today::TaskState value, const ResolverParams&) - { - response::Value result(response::Type::EnumValue); - - result.set(response::StringType { s_namesTaskState[static_cast(value)] }); - - return result; - }); -} - -template <> -today::CompleteTaskInput ModifiedArgument::convert(const response::Value& value) -{ - const auto defaultValue = []() - { - response::Value values(response::Type::Map); - response::Value entry; - - entry = response::Value(true); - values.emplace_back("isComplete", std::move(entry)); - - return values; - }(); - - auto valueId = service::ModifiedArgument::require("id", value); - auto valueTestTaskState = service::ModifiedArgument::require("testTaskState", value); - auto pairIsComplete = service::ModifiedArgument::find("isComplete", value); - auto valueIsComplete = (pairIsComplete.second - ? std::move(pairIsComplete.first) - : service::ModifiedArgument::require("isComplete", defaultValue)); - auto valueClientMutationId = service::ModifiedArgument::require("clientMutationId", value); - - return { - std::move(valueId), - std::move(valueTestTaskState), - std::move(valueIsComplete), - std::move(valueClientMutationId) - }; -} - -template <> -today::ThirdNestedInput ModifiedArgument::convert(const response::Value& value) -{ - auto valueId = service::ModifiedArgument::require("id", value); - - return { - std::move(valueId) - }; -} - -template <> -today::FourthNestedInput ModifiedArgument::convert(const response::Value& value) -{ - auto valueId = service::ModifiedArgument::require("id", value); - - return { - std::move(valueId) - }; -} - -template <> -today::SecondNestedInput ModifiedArgument::convert(const response::Value& value) -{ - auto valueId = service::ModifiedArgument::require("id", value); - auto valueThird = service::ModifiedArgument::require("third", value); - - return { - std::move(valueId), - std::move(valueThird) - }; -} - -template <> -today::FirstNestedInput ModifiedArgument::convert(const response::Value& value) -{ - auto valueId = service::ModifiedArgument::require("id", value); - auto valueSecond = service::ModifiedArgument::require("second", value); - auto valueThird = service::ModifiedArgument::require("third", value); - - return { - std::move(valueId), - std::move(valueSecond), - std::move(valueThird) - }; -} - -} // namespace service - -namespace today { -namespace object { - -Query::Query() - : service::Object({ - "Query" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(tasks)gql"sv, [this](service::ResolverParams&& params) { return resolveTasks(std::move(params)); } }, - { R"gql(__type)gql"sv, [this](service::ResolverParams&& params) { return resolve_type(std::move(params)); } }, - { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } }, - { R"gql(anyType)gql"sv, [this](service::ResolverParams&& params) { return resolveAnyType(std::move(params)); } }, - { R"gql(__schema)gql"sv, [this](service::ResolverParams&& params) { return resolve_schema(std::move(params)); } }, - { R"gql(expensive)gql"sv, [this](service::ResolverParams&& params) { return resolveExpensive(std::move(params)); } }, - { R"gql(tasksById)gql"sv, [this](service::ResolverParams&& params) { return resolveTasksById(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(appointments)gql"sv, [this](service::ResolverParams&& params) { return resolveAppointments(std::move(params)); } }, - { R"gql(unreadCounts)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCounts(std::move(params)); } }, - { R"gql(testTaskState)gql"sv, [this](service::ResolverParams&& params) { return resolveTestTaskState(std::move(params)); } }, - { R"gql(unimplemented)gql"sv, [this](service::ResolverParams&& params) { return resolveUnimplemented(std::move(params)); } }, - { R"gql(appointmentsById)gql"sv, [this](service::ResolverParams&& params) { return resolveAppointmentsById(std::move(params)); } }, - { R"gql(unreadCountsById)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCountsById(std::move(params)); } } - }) - , _schema(GetSchema()) -{ -} - -service::FieldResult> Query::getNode(service::FieldParams&&, response::IdType&&) const -{ - throw std::runtime_error(R"ex(Query::getNode is not implemented)ex"); -} - -std::future Query::resolveNode(service::ResolverParams&& params) -{ - auto argId = service::ModifiedArgument::require("id", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getAppointments(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getAppointments is not implemented)ex"); -} - -std::future Query::resolveAppointments(service::ResolverParams&& params) -{ - auto argFirst = service::ModifiedArgument::require("first", params.arguments); - auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); - auto argBefore = service::ModifiedArgument::require("before", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getAppointments(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getTasks(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getTasks is not implemented)ex"); -} - -std::future Query::resolveTasks(service::ResolverParams&& params) -{ - auto argFirst = service::ModifiedArgument::require("first", params.arguments); - auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); - auto argBefore = service::ModifiedArgument::require("before", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTasks(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getUnreadCounts(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getUnreadCounts is not implemented)ex"); -} - -std::future Query::resolveUnreadCounts(service::ResolverParams&& params) -{ - auto argFirst = service::ModifiedArgument::require("first", params.arguments); - auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); - auto argBefore = service::ModifiedArgument::require("before", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCounts(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Query::getAppointmentsById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getAppointmentsById is not implemented)ex"); -} - -std::future Query::resolveAppointmentsById(service::ResolverParams&& params) -{ - const auto defaultArguments = []() - { - response::Value values(response::Type::Map); - response::Value entry; - - entry = []() - { - response::Value elements(response::Type::List); - response::Value entry; - - entry = response::Value(std::string(R"gql(ZmFrZUFwcG9pbnRtZW50SWQ=)gql")); - elements.emplace_back(std::move(entry)); - return elements; - }(); - values.emplace_back("ids", std::move(entry)); - - return values; - }(); - - auto pairIds = service::ModifiedArgument::find("ids", params.arguments); - auto argIds = (pairIds.second - ? std::move(pairIds.first) - : service::ModifiedArgument::require("ids", defaultArguments)); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getAppointmentsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Query::getTasksById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getTasksById is not implemented)ex"); -} - -std::future Query::resolveTasksById(service::ResolverParams&& params) -{ - auto argIds = service::ModifiedArgument::require("ids", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTasksById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Query::getUnreadCountsById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getUnreadCountsById is not implemented)ex"); -} - -std::future Query::resolveUnreadCountsById(service::ResolverParams&& params) -{ - auto argIds = service::ModifiedArgument::require("ids", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCountsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getNested(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getNested is not implemented)ex"); -} - -std::future Query::resolveNested(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Query::getUnimplemented(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getUnimplemented is not implemented)ex"); -} - -std::future Query::resolveUnimplemented(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getUnimplemented(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Query::getExpensive(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getExpensive is not implemented)ex"); -} - -std::future Query::resolveExpensive(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getExpensive(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Query::getTestTaskState(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getTestTaskState is not implemented)ex"); -} - -std::future Query::resolveTestTaskState(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTestTaskState(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Query::getAnyType(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getAnyType is not implemented)ex"); -} - -std::future Query::resolveAnyType(service::ResolverParams&& params) -{ - auto argIds = service::ModifiedArgument::require("ids", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getAnyType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Query::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Query)gql" }, std::move(params)); -} - -std::future Query::resolve_schema(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(std::static_pointer_cast(std::make_shared(_schema)), std::move(params)); -} - -std::future Query::resolve_type(service::ResolverParams&& params) -{ - auto argName = service::ModifiedArgument::require("name", params.arguments); - const auto& baseType = _schema->LookupType(argName); - std::shared_ptr result { baseType ? std::make_shared(baseType) : nullptr }; - - return service::ModifiedResult::convert(result, std::move(params)); -} - -PageInfo::PageInfo() - : service::Object({ - "PageInfo" - }, { - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(hasNextPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasNextPage(std::move(params)); } }, - { R"gql(hasPreviousPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasPreviousPage(std::move(params)); } } - }) -{ -} - -service::FieldResult PageInfo::getHasNextPage(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(PageInfo::getHasNextPage is not implemented)ex"); -} - -std::future PageInfo::resolveHasNextPage(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHasNextPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult PageInfo::getHasPreviousPage(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(PageInfo::getHasPreviousPage is not implemented)ex"); -} - -std::future PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHasPreviousPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future PageInfo::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(PageInfo)gql" }, std::move(params)); -} - -AppointmentEdge::AppointmentEdge() - : service::Object({ - "AppointmentEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> AppointmentEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentEdge::getNode is not implemented)ex"); -} - -std::future AppointmentEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult AppointmentEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentEdge::getCursor is not implemented)ex"); -} - -std::future AppointmentEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future AppointmentEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentEdge)gql" }, std::move(params)); -} - -AppointmentConnection::AppointmentConnection() - : service::Object({ - "AppointmentConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> AppointmentConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentConnection::getPageInfo is not implemented)ex"); -} - -std::future AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> AppointmentConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentConnection::getEdges is not implemented)ex"); -} - -std::future AppointmentConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future AppointmentConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentConnection)gql" }, std::move(params)); -} - -TaskEdge::TaskEdge() - : service::Object({ - "TaskEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> TaskEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskEdge::getNode is not implemented)ex"); -} - -std::future TaskEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult TaskEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskEdge::getCursor is not implemented)ex"); -} - -std::future TaskEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future TaskEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(TaskEdge)gql" }, std::move(params)); -} - -TaskConnection::TaskConnection() - : service::Object({ - "TaskConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> TaskConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskConnection::getPageInfo is not implemented)ex"); -} - -std::future TaskConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> TaskConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskConnection::getEdges is not implemented)ex"); -} - -std::future TaskConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future TaskConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(TaskConnection)gql" }, std::move(params)); -} - -FolderEdge::FolderEdge() - : service::Object({ - "FolderEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> FolderEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderEdge::getNode is not implemented)ex"); -} - -std::future FolderEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult FolderEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderEdge::getCursor is not implemented)ex"); -} - -std::future FolderEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future FolderEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(FolderEdge)gql" }, std::move(params)); -} - -FolderConnection::FolderConnection() - : service::Object({ - "FolderConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> FolderConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderConnection::getPageInfo is not implemented)ex"); -} - -std::future FolderConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> FolderConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderConnection::getEdges is not implemented)ex"); -} - -std::future FolderConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future FolderConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(FolderConnection)gql" }, std::move(params)); -} - -CompleteTaskPayload::CompleteTaskPayload() - : service::Object({ - "CompleteTaskPayload" - }, { - { R"gql(task)gql"sv, [this](service::ResolverParams&& params) { return resolveTask(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(clientMutationId)gql"sv, [this](service::ResolverParams&& params) { return resolveClientMutationId(std::move(params)); } } - }) -{ -} - -service::FieldResult> CompleteTaskPayload::getTask(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(CompleteTaskPayload::getTask is not implemented)ex"); -} - -std::future CompleteTaskPayload::resolveTask(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> CompleteTaskPayload::getClientMutationId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(CompleteTaskPayload::getClientMutationId is not implemented)ex"); -} - -std::future CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getClientMutationId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(CompleteTaskPayload)gql" }, std::move(params)); -} - -Mutation::Mutation() - : service::Object({ - "Mutation" - }, { - { R"gql(setFloat)gql"sv, [this](service::ResolverParams&& params) { return resolveSetFloat(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(completeTask)gql"sv, [this](service::ResolverParams&& params) { return resolveCompleteTask(std::move(params)); } } - }) -{ -} - -service::FieldResult> Mutation::applyCompleteTask(service::FieldParams&&, CompleteTaskInput&&) const -{ - throw std::runtime_error(R"ex(Mutation::applyCompleteTask is not implemented)ex"); -} - -std::future Mutation::resolveCompleteTask(service::ResolverParams&& params) -{ - auto argInput = service::ModifiedArgument::require("input", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = applyCompleteTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argInput)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Mutation::applySetFloat(service::FieldParams&&, response::FloatType&&) const -{ - throw std::runtime_error(R"ex(Mutation::applySetFloat is not implemented)ex"); -} - -std::future Mutation::resolveSetFloat(service::ResolverParams&& params) -{ - auto argValue = service::ModifiedArgument::require("value", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = applySetFloat(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argValue)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Mutation::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Mutation)gql" }, std::move(params)); -} - -Subscription::Subscription() - : service::Object({ - "Subscription" - }, { - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(nodeChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNodeChange(std::move(params)); } }, - { R"gql(nextAppointmentChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNextAppointmentChange(std::move(params)); } } - }) -{ -} - -service::FieldResult> Subscription::getNextAppointmentChange(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Subscription::getNextAppointmentChange is not implemented)ex"); -} - -std::future Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNextAppointmentChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Subscription::getNodeChange(service::FieldParams&&, response::IdType&&) const -{ - throw std::runtime_error(R"ex(Subscription::getNodeChange is not implemented)ex"); -} - -std::future Subscription::resolveNodeChange(service::ResolverParams&& params) -{ - auto argId = service::ModifiedArgument::require("id", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNodeChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Subscription::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Subscription)gql" }, std::move(params)); -} - -Appointment::Appointment() - : service::Object({ - "Node", - "UnionType", - "Appointment" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(when)gql"sv, [this](service::ResolverParams&& params) { return resolveWhen(std::move(params)); } }, - { R"gql(isNow)gql"sv, [this](service::ResolverParams&& params) { return resolveIsNow(std::move(params)); } }, - { R"gql(subject)gql"sv, [this](service::ResolverParams&& params) { return resolveSubject(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(forceError)gql"sv, [this](service::ResolverParams&& params) { return resolveForceError(std::move(params)); } } - }) -{ -} - -service::FieldResult Appointment::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); -} - -std::future Appointment::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getWhen(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getWhen is not implemented)ex"); -} - -std::future Appointment::resolveWhen(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getWhen(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getSubject(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getSubject is not implemented)ex"); -} - -std::future Appointment::resolveSubject(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getSubject(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Appointment::getIsNow(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getIsNow is not implemented)ex"); -} - -std::future Appointment::resolveIsNow(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getIsNow(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getForceError(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getForceError is not implemented)ex"); -} - -std::future Appointment::resolveForceError(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getForceError(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Appointment::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Appointment)gql" }, std::move(params)); -} - -Task::Task() - : service::Object({ - "Node", - "UnionType", - "Task" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(title)gql"sv, [this](service::ResolverParams&& params) { return resolveTitle(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(isComplete)gql"sv, [this](service::ResolverParams&& params) { return resolveIsComplete(std::move(params)); } } - }) -{ -} - -service::FieldResult Task::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Task::getId is not implemented)ex"); -} - -std::future Task::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Task::getTitle(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Task::getTitle is not implemented)ex"); -} - -std::future Task::resolveTitle(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTitle(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Task::getIsComplete(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Task::getIsComplete is not implemented)ex"); -} - -std::future Task::resolveIsComplete(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getIsComplete(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Task::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Task)gql" }, std::move(params)); -} - -Folder::Folder() - : service::Object({ - "Node", - "UnionType", - "Folder" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(unreadCount)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCount(std::move(params)); } } - }) -{ -} - -service::FieldResult Folder::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getId is not implemented)ex"); -} - -std::future Folder::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Folder::getName(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getName is not implemented)ex"); -} - -std::future Folder::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Folder::getUnreadCount(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getUnreadCount is not implemented)ex"); -} - -std::future Folder::resolveUnreadCount(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCount(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Folder::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Folder)gql" }, std::move(params)); -} - -NestedType::NestedType() - : service::Object({ - "NestedType" - }, { - { R"gql(depth)gql"sv, [this](service::ResolverParams&& params) { return resolveDepth(std::move(params)); } }, - { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult NestedType::getDepth(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(NestedType::getDepth is not implemented)ex"); -} - -std::future NestedType::resolveDepth(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDepth(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> NestedType::getNested(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(NestedType::getNested is not implemented)ex"); -} - -std::future NestedType::resolveNested(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future NestedType::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(NestedType)gql" }, std::move(params)); -} - -Expensive::Expensive() - : service::Object({ - "Expensive" - }, { - { R"gql(order)gql"sv, [this](service::ResolverParams&& params) { return resolveOrder(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult Expensive::getOrder(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Expensive::getOrder is not implemented)ex"); -} - -std::future Expensive::resolveOrder(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getOrder(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Expensive::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Expensive)gql" }, std::move(params)); -} - -} // namespace object - -Operations::Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription) - : service::Request({ - { "query", query }, - { "mutation", mutation }, - { "subscription", subscription } - }, GetSchema()) - , _query(std::move(query)) - , _mutation(std::move(mutation)) - , _subscription(std::move(subscription)) -{ -} - -void AddTypesToSchema(const std::shared_ptr& schema) -{ - schema->AddType(R"gql(ItemCursor)gql"sv, schema::ScalarType::Make(R"gql(ItemCursor)gql"sv, R"md()md")); - schema->AddType(R"gql(DateTime)gql"sv, schema::ScalarType::Make(R"gql(DateTime)gql"sv, R"md()md")); - auto typeTaskState = schema::EnumType::Make(R"gql(TaskState)gql"sv, R"md()md"sv); - schema->AddType(R"gql(TaskState)gql"sv, typeTaskState); - auto typeCompleteTaskInput = schema::InputObjectType::Make(R"gql(CompleteTaskInput)gql"sv, R"md()md"sv); - schema->AddType(R"gql(CompleteTaskInput)gql"sv, typeCompleteTaskInput); - auto typeThirdNestedInput = schema::InputObjectType::Make(R"gql(ThirdNestedInput)gql"sv, R"md()md"sv); - schema->AddType(R"gql(ThirdNestedInput)gql"sv, typeThirdNestedInput); - auto typeFourthNestedInput = schema::InputObjectType::Make(R"gql(FourthNestedInput)gql"sv, R"md()md"sv); - schema->AddType(R"gql(FourthNestedInput)gql"sv, typeFourthNestedInput); - auto typeSecondNestedInput = schema::InputObjectType::Make(R"gql(SecondNestedInput)gql"sv, R"md()md"sv); - schema->AddType(R"gql(SecondNestedInput)gql"sv, typeSecondNestedInput); - auto typeFirstNestedInput = schema::InputObjectType::Make(R"gql(FirstNestedInput)gql"sv, R"md()md"sv); - schema->AddType(R"gql(FirstNestedInput)gql"sv, typeFirstNestedInput); - auto typeUnionType = schema::UnionType::Make(R"gql(UnionType)gql"sv, R"md()md"sv); - schema->AddType(R"gql(UnionType)gql"sv, typeUnionType); - auto typeNode = schema::InterfaceType::Make(R"gql(Node)gql"sv, R"md(Node interface for Relay support)md"sv); - schema->AddType(R"gql(Node)gql"sv, typeNode); - auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md(Root Query type)md"); - schema->AddType(R"gql(Query)gql"sv, typeQuery); - auto typePageInfo = schema::ObjectType::Make(R"gql(PageInfo)gql"sv, R"md()md"); - schema->AddType(R"gql(PageInfo)gql"sv, typePageInfo); - auto typeAppointmentEdge = schema::ObjectType::Make(R"gql(AppointmentEdge)gql"sv, R"md()md"); - schema->AddType(R"gql(AppointmentEdge)gql"sv, typeAppointmentEdge); - auto typeAppointmentConnection = schema::ObjectType::Make(R"gql(AppointmentConnection)gql"sv, R"md()md"); - schema->AddType(R"gql(AppointmentConnection)gql"sv, typeAppointmentConnection); - auto typeTaskEdge = schema::ObjectType::Make(R"gql(TaskEdge)gql"sv, R"md()md"); - schema->AddType(R"gql(TaskEdge)gql"sv, typeTaskEdge); - auto typeTaskConnection = schema::ObjectType::Make(R"gql(TaskConnection)gql"sv, R"md()md"); - schema->AddType(R"gql(TaskConnection)gql"sv, typeTaskConnection); - auto typeFolderEdge = schema::ObjectType::Make(R"gql(FolderEdge)gql"sv, R"md()md"); - schema->AddType(R"gql(FolderEdge)gql"sv, typeFolderEdge); - auto typeFolderConnection = schema::ObjectType::Make(R"gql(FolderConnection)gql"sv, R"md()md"); - schema->AddType(R"gql(FolderConnection)gql"sv, typeFolderConnection); - auto typeCompleteTaskPayload = schema::ObjectType::Make(R"gql(CompleteTaskPayload)gql"sv, R"md()md"); - schema->AddType(R"gql(CompleteTaskPayload)gql"sv, typeCompleteTaskPayload); - auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"); - schema->AddType(R"gql(Mutation)gql"sv, typeMutation); - auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"); - schema->AddType(R"gql(Subscription)gql"sv, typeSubscription); - auto typeAppointment = schema::ObjectType::Make(R"gql(Appointment)gql"sv, R"md()md"); - schema->AddType(R"gql(Appointment)gql"sv, typeAppointment); - auto typeTask = schema::ObjectType::Make(R"gql(Task)gql"sv, R"md()md"); - schema->AddType(R"gql(Task)gql"sv, typeTask); - auto typeFolder = schema::ObjectType::Make(R"gql(Folder)gql"sv, R"md()md"); - schema->AddType(R"gql(Folder)gql"sv, typeFolder); - auto typeNestedType = schema::ObjectType::Make(R"gql(NestedType)gql"sv, R"md(Infinitely nestable type which can be used with nested fragments to test directive handling)md"); - schema->AddType(R"gql(NestedType)gql"sv, typeNestedType); - auto typeExpensive = schema::ObjectType::Make(R"gql(Expensive)gql"sv, R"md()md"); - schema->AddType(R"gql(Expensive)gql"sv, typeExpensive); - - typeTaskState->AddEnumValues({ - { service::s_namesTaskState[static_cast(today::TaskState::New)], R"md()md"sv, std::nullopt }, - { service::s_namesTaskState[static_cast(today::TaskState::Started)], R"md()md"sv, std::nullopt }, - { service::s_namesTaskState[static_cast(today::TaskState::Complete)], R"md()md"sv, std::nullopt }, - { service::s_namesTaskState[static_cast(today::TaskState::Unassigned)], R"md()md"sv, std::make_optional(R"md(Need to deprecate an [enum value](http://spec.graphql.org/June2018/#sec-Deprecation))md"sv) } - }); - - typeCompleteTaskInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, schema->LookupType("TaskState"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(isComplete)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(true)gql"sv), - schema::InputValue::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) - }); - typeThirdNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) - }); - typeFourthNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) - }); - typeSecondNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ThirdNestedInput")), R"gql()gql"sv) - }); - typeFirstNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(second)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("SecondNestedInput")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ThirdNestedInput")), R"gql()gql"sv) - }); - - typeUnionType->AddPossibleTypes({ - schema->LookupType(R"gql(Appointment)gql"sv), - schema->LookupType(R"gql(Task)gql"sv), - schema->LookupType(R"gql(Folder)gql"sv) - }); - - typeNode->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) - }); - - typeQuery->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md([Object Identification](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#object-identification))md"sv, std::nullopt, schema->LookupType("Node"), { - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(appointments)gql"sv, R"md(Appointments [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("AppointmentConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(tasks)gql"sv, R"md(Tasks [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(unreadCounts)gql"sv, R"md(Folder unread counts [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("FolderConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(appointmentsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Appointment"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql"sv) - }), - schema::Field::Make(R"gql(tasksById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Task"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(unreadCountsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Folder"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))), - schema::Field::Make(R"gql(unimplemented)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(expensive)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Expensive"))))), - schema::Field::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskState"))), - schema::Field::Make(R"gql(anyType)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("UnionType"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) - }) - }); - typePageInfo->AddFields({ - schema::Field::Make(R"gql(hasNextPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - schema::Field::Make(R"gql(hasPreviousPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) - }); - typeAppointmentEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Appointment")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); - typeAppointmentConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))) - }); - typeTaskEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); - typeTaskConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))) - }); - typeFolderEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Folder")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); - typeFolderConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))) - }); - typeCompleteTaskPayload->AddFields({ - schema::Field::Make(R"gql(task)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), - schema::Field::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); - typeMutation->AddFields({ - schema::Field::Make(R"gql(completeTask)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskPayload")), { - schema::InputValue::Make(R"gql(input)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskInput")), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(setFloat)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), { - schema::InputValue::Make(R"gql(value)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), R"gql()gql"sv) - }) - }); - typeSubscription->AddFields({ - schema::Field::Make(R"gql(nextAppointmentChange)gql"sv, R"md()md"sv, std::make_optional(R"md(Need to deprecate a [field](http://spec.graphql.org/June2018/#sec-Deprecation))md"sv), schema->LookupType("Appointment")), - schema::Field::Make(R"gql(nodeChange)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Node")), { - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) - }) - }); - typeAppointment->AddInterfaces({ - typeNode - }); - typeAppointment->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(when)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("DateTime")), - schema::Field::Make(R"gql(subject)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(isNow)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - schema::Field::Make(R"gql(forceError)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); - typeTask->AddInterfaces({ - typeNode - }); - typeTask->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(title)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(isComplete)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) - }); - typeFolder->AddInterfaces({ - typeNode - }); - typeFolder->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(unreadCount)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) - }); - typeNestedType->AddFields({ - schema::Field::Make(R"gql(depth)gql"sv, R"md(Depth of the nested element)md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), - schema::Field::Make(R"gql(nested)gql"sv, R"md(Link to the next level)md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))) - }); - typeExpensive->AddFields({ - schema::Field::Make(R"gql(order)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) - }); - - schema->AddDirective(schema::Directive::Make(R"gql(id)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::FIELD_DEFINITION - })); - schema->AddDirective(schema::Directive::Make(R"gql(subscriptionTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::SUBSCRIPTION - }, { - schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(queryTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::QUERY - }, { - schema::InputValue::Make(R"gql(query)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(fieldTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::FIELD - }, { - schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(fragmentDefinitionTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::FRAGMENT_DEFINITION - }, { - schema::InputValue::Make(R"gql(fragmentDefinition)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(fragmentSpreadTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::FRAGMENT_SPREAD - }, { - schema::InputValue::Make(R"gql(fragmentSpread)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(inlineFragmentTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::INLINE_FRAGMENT - }, { - schema::InputValue::Make(R"gql(inlineFragment)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); - - schema->AddQueryType(typeQuery); - schema->AddMutationType(typeMutation); - schema->AddSubscriptionType(typeSubscription); -} - -std::shared_ptr GetSchema() -{ - static std::weak_ptr s_wpSchema; - auto schema = s_wpSchema.lock(); - - if (!schema) - { - schema = std::make_shared(false); - introspection::AddTypesToSchema(schema); - AddTypesToSchema(schema); - s_wpSchema = schema; - } - - return schema; -} - -} // namespace today -} // namespace graphql diff --git a/samples/unified/TodaySchema.h b/samples/unified/TodaySchema.h deleted file mode 100644 index 8eac4e5f..00000000 --- a/samples/unified/TodaySchema.h +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TODAYSCHEMA_H -#define TODAYSCHEMA_H - -#include "graphqlservice/internal/Schema.h" - -// Check if the library version is compatible with schemagen 3.6.0 -static_assert(graphql::internal::MajorVersion == 3, "regenerate with schemagen: major version mismatch"); -static_assert(graphql::internal::MinorVersion == 6, "regenerate with schemagen: minor version mismatch"); - -#include -#include -#include - -namespace graphql { -namespace today { - -enum class TaskState -{ - New, - Started, - Complete, - Unassigned -}; - -struct CompleteTaskInput -{ - response::IdType id; - std::optional testTaskState; - std::optional isComplete; - std::optional clientMutationId; -}; - -struct ThirdNestedInput -{ - response::IdType id; -}; - -struct FourthNestedInput -{ - response::IdType id; -}; - -struct SecondNestedInput -{ - response::IdType id; - ThirdNestedInput third; -}; - -struct FirstNestedInput -{ - response::IdType id; - SecondNestedInput second; - ThirdNestedInput third; -}; - -namespace object { - -class Query; -class PageInfo; -class AppointmentEdge; -class AppointmentConnection; -class TaskEdge; -class TaskConnection; -class FolderEdge; -class FolderConnection; -class CompleteTaskPayload; -class Mutation; -class Subscription; -class Appointment; -class Task; -class Folder; -class NestedType; -class Expensive; - -} // namespace object - -struct Node -{ - virtual service::FieldResult getId(service::FieldParams&& params) const = 0; -}; - -namespace object { - -class Query - : public service::Object -{ -protected: - explicit Query(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params, response::IdType&& idArg) const; - virtual service::FieldResult> getAppointments(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult> getTasks(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult> getUnreadCounts(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult>> getAppointmentsById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult>> getTasksById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult>> getUnreadCountsById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult> getNested(service::FieldParams&& params) const; - virtual service::FieldResult getUnimplemented(service::FieldParams&& params) const; - virtual service::FieldResult>> getExpensive(service::FieldParams&& params) const; - virtual service::FieldResult getTestTaskState(service::FieldParams&& params) const; - virtual service::FieldResult>> getAnyType(service::FieldParams&& params, std::vector&& idsArg) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveAppointments(service::ResolverParams&& params); - std::future resolveTasks(service::ResolverParams&& params); - std::future resolveUnreadCounts(service::ResolverParams&& params); - std::future resolveAppointmentsById(service::ResolverParams&& params); - std::future resolveTasksById(service::ResolverParams&& params); - std::future resolveUnreadCountsById(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); - std::future resolveUnimplemented(service::ResolverParams&& params); - std::future resolveExpensive(service::ResolverParams&& params); - std::future resolveTestTaskState(service::ResolverParams&& params); - std::future resolveAnyType(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); - std::future resolve_schema(service::ResolverParams&& params); - std::future resolve_type(service::ResolverParams&& params); - - std::shared_ptr _schema; -}; - -class PageInfo - : public service::Object -{ -protected: - explicit PageInfo(); - -public: - virtual service::FieldResult getHasNextPage(service::FieldParams&& params) const; - virtual service::FieldResult getHasPreviousPage(service::FieldParams&& params) const; - -private: - std::future resolveHasNextPage(service::ResolverParams&& params); - std::future resolveHasPreviousPage(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class AppointmentEdge - : public service::Object -{ -protected: - explicit AppointmentEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class AppointmentConnection - : public service::Object -{ -protected: - explicit AppointmentConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class TaskEdge - : public service::Object -{ -protected: - explicit TaskEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class TaskConnection - : public service::Object -{ -protected: - explicit TaskConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class FolderEdge - : public service::Object -{ -protected: - explicit FolderEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class FolderConnection - : public service::Object -{ -protected: - explicit FolderConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class CompleteTaskPayload - : public service::Object -{ -protected: - explicit CompleteTaskPayload(); - -public: - virtual service::FieldResult> getTask(service::FieldParams&& params) const; - virtual service::FieldResult> getClientMutationId(service::FieldParams&& params) const; - -private: - std::future resolveTask(service::ResolverParams&& params); - std::future resolveClientMutationId(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Mutation - : public service::Object -{ -protected: - explicit Mutation(); - -public: - virtual service::FieldResult> applyCompleteTask(service::FieldParams&& params, CompleteTaskInput&& inputArg) const; - virtual service::FieldResult applySetFloat(service::FieldParams&& params, response::FloatType&& valueArg) const; - -private: - std::future resolveCompleteTask(service::ResolverParams&& params); - std::future resolveSetFloat(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Subscription - : public service::Object -{ -protected: - explicit Subscription(); - -public: - virtual service::FieldResult> getNextAppointmentChange(service::FieldParams&& params) const; - virtual service::FieldResult> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const; - -private: - std::future resolveNextAppointmentChange(service::ResolverParams&& params); - std::future resolveNodeChange(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Appointment - : public service::Object - , public Node -{ -protected: - explicit Appointment(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getWhen(service::FieldParams&& params) const; - virtual service::FieldResult> getSubject(service::FieldParams&& params) const; - virtual service::FieldResult getIsNow(service::FieldParams&& params) const; - virtual service::FieldResult> getForceError(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveWhen(service::ResolverParams&& params); - std::future resolveSubject(service::ResolverParams&& params); - std::future resolveIsNow(service::ResolverParams&& params); - std::future resolveForceError(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Task - : public service::Object - , public Node -{ -protected: - explicit Task(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getTitle(service::FieldParams&& params) const; - virtual service::FieldResult getIsComplete(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveTitle(service::ResolverParams&& params); - std::future resolveIsComplete(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Folder - : public service::Object - , public Node -{ -protected: - explicit Folder(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getName(service::FieldParams&& params) const; - virtual service::FieldResult getUnreadCount(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveName(service::ResolverParams&& params); - std::future resolveUnreadCount(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class NestedType - : public service::Object -{ -protected: - explicit NestedType(); - -public: - virtual service::FieldResult getDepth(service::FieldParams&& params) const; - virtual service::FieldResult> getNested(service::FieldParams&& params) const; - -private: - std::future resolveDepth(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Expensive - : public service::Object -{ -protected: - explicit Expensive(); - -public: - virtual service::FieldResult getOrder(service::FieldParams&& params) const; - -private: - std::future resolveOrder(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace object - -class Operations - : public service::Request -{ -public: - explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription); - -private: - std::shared_ptr _query; - std::shared_ptr _mutation; - std::shared_ptr _subscription; -}; - -std::shared_ptr GetSchema(); - -} // namespace today -} // namespace graphql - -#endif // TODAYSCHEMA_H diff --git a/samples/unified_nointrospection/TodaySchema.cpp b/samples/unified_nointrospection/TodaySchema.cpp deleted file mode 100644 index 8d9464c6..00000000 --- a/samples/unified_nointrospection/TodaySchema.cpp +++ /dev/null @@ -1,1433 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "TodaySchema.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql { -namespace service { - -static const std::array s_namesTaskState = { - "New"sv, - "Started"sv, - "Complete"sv, - "Unassigned"sv -}; - -template <> -today::TaskState ModifiedArgument::convert(const response::Value& value) -{ - if (!value.maybe_enum()) - { - throw service::schema_exception { { "not a valid TaskState value" } }; - } - - const auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.get()); - - if (itr == s_namesTaskState.cend()) - { - throw service::schema_exception { { "not a valid TaskState value" } }; - } - - return static_cast(itr - s_namesTaskState.cbegin()); -} - -template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) -{ - return resolve(std::move(result), std::move(params), - [](today::TaskState value, const ResolverParams&) - { - response::Value result(response::Type::EnumValue); - - result.set(response::StringType { s_namesTaskState[static_cast(value)] }); - - return result; - }); -} - -template <> -today::CompleteTaskInput ModifiedArgument::convert(const response::Value& value) -{ - const auto defaultValue = []() - { - response::Value values(response::Type::Map); - response::Value entry; - - entry = response::Value(true); - values.emplace_back("isComplete", std::move(entry)); - - return values; - }(); - - auto valueId = service::ModifiedArgument::require("id", value); - auto valueTestTaskState = service::ModifiedArgument::require("testTaskState", value); - auto pairIsComplete = service::ModifiedArgument::find("isComplete", value); - auto valueIsComplete = (pairIsComplete.second - ? std::move(pairIsComplete.first) - : service::ModifiedArgument::require("isComplete", defaultValue)); - auto valueClientMutationId = service::ModifiedArgument::require("clientMutationId", value); - - return { - std::move(valueId), - std::move(valueTestTaskState), - std::move(valueIsComplete), - std::move(valueClientMutationId) - }; -} - -template <> -today::ThirdNestedInput ModifiedArgument::convert(const response::Value& value) -{ - auto valueId = service::ModifiedArgument::require("id", value); - - return { - std::move(valueId) - }; -} - -template <> -today::FourthNestedInput ModifiedArgument::convert(const response::Value& value) -{ - auto valueId = service::ModifiedArgument::require("id", value); - - return { - std::move(valueId) - }; -} - -template <> -today::SecondNestedInput ModifiedArgument::convert(const response::Value& value) -{ - auto valueId = service::ModifiedArgument::require("id", value); - auto valueThird = service::ModifiedArgument::require("third", value); - - return { - std::move(valueId), - std::move(valueThird) - }; -} - -template <> -today::FirstNestedInput ModifiedArgument::convert(const response::Value& value) -{ - auto valueId = service::ModifiedArgument::require("id", value); - auto valueSecond = service::ModifiedArgument::require("second", value); - auto valueThird = service::ModifiedArgument::require("third", value); - - return { - std::move(valueId), - std::move(valueSecond), - std::move(valueThird) - }; -} - -} // namespace service - -namespace today { -namespace object { - -Query::Query() - : service::Object({ - "Query" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(tasks)gql"sv, [this](service::ResolverParams&& params) { return resolveTasks(std::move(params)); } }, - { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } }, - { R"gql(anyType)gql"sv, [this](service::ResolverParams&& params) { return resolveAnyType(std::move(params)); } }, - { R"gql(expensive)gql"sv, [this](service::ResolverParams&& params) { return resolveExpensive(std::move(params)); } }, - { R"gql(tasksById)gql"sv, [this](service::ResolverParams&& params) { return resolveTasksById(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(appointments)gql"sv, [this](service::ResolverParams&& params) { return resolveAppointments(std::move(params)); } }, - { R"gql(unreadCounts)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCounts(std::move(params)); } }, - { R"gql(testTaskState)gql"sv, [this](service::ResolverParams&& params) { return resolveTestTaskState(std::move(params)); } }, - { R"gql(unimplemented)gql"sv, [this](service::ResolverParams&& params) { return resolveUnimplemented(std::move(params)); } }, - { R"gql(appointmentsById)gql"sv, [this](service::ResolverParams&& params) { return resolveAppointmentsById(std::move(params)); } }, - { R"gql(unreadCountsById)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCountsById(std::move(params)); } } - }) -{ -} - -service::FieldResult> Query::getNode(service::FieldParams&&, response::IdType&&) const -{ - throw std::runtime_error(R"ex(Query::getNode is not implemented)ex"); -} - -std::future Query::resolveNode(service::ResolverParams&& params) -{ - auto argId = service::ModifiedArgument::require("id", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getAppointments(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getAppointments is not implemented)ex"); -} - -std::future Query::resolveAppointments(service::ResolverParams&& params) -{ - auto argFirst = service::ModifiedArgument::require("first", params.arguments); - auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); - auto argBefore = service::ModifiedArgument::require("before", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getAppointments(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getTasks(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getTasks is not implemented)ex"); -} - -std::future Query::resolveTasks(service::ResolverParams&& params) -{ - auto argFirst = service::ModifiedArgument::require("first", params.arguments); - auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); - auto argBefore = service::ModifiedArgument::require("before", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTasks(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getUnreadCounts(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getUnreadCounts is not implemented)ex"); -} - -std::future Query::resolveUnreadCounts(service::ResolverParams&& params) -{ - auto argFirst = service::ModifiedArgument::require("first", params.arguments); - auto argAfter = service::ModifiedArgument::require("after", params.arguments); - auto argLast = service::ModifiedArgument::require("last", params.arguments); - auto argBefore = service::ModifiedArgument::require("before", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCounts(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Query::getAppointmentsById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getAppointmentsById is not implemented)ex"); -} - -std::future Query::resolveAppointmentsById(service::ResolverParams&& params) -{ - const auto defaultArguments = []() - { - response::Value values(response::Type::Map); - response::Value entry; - - entry = []() - { - response::Value elements(response::Type::List); - response::Value entry; - - entry = response::Value(std::string(R"gql(ZmFrZUFwcG9pbnRtZW50SWQ=)gql")); - elements.emplace_back(std::move(entry)); - return elements; - }(); - values.emplace_back("ids", std::move(entry)); - - return values; - }(); - - auto pairIds = service::ModifiedArgument::find("ids", params.arguments); - auto argIds = (pairIds.second - ? std::move(pairIds.first) - : service::ModifiedArgument::require("ids", defaultArguments)); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getAppointmentsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Query::getTasksById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getTasksById is not implemented)ex"); -} - -std::future Query::resolveTasksById(service::ResolverParams&& params) -{ - auto argIds = service::ModifiedArgument::require("ids", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTasksById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Query::getUnreadCountsById(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getUnreadCountsById is not implemented)ex"); -} - -std::future Query::resolveUnreadCountsById(service::ResolverParams&& params) -{ - auto argIds = service::ModifiedArgument::require("ids", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCountsById(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getNested(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getNested is not implemented)ex"); -} - -std::future Query::resolveNested(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Query::getUnimplemented(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getUnimplemented is not implemented)ex"); -} - -std::future Query::resolveUnimplemented(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getUnimplemented(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Query::getExpensive(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getExpensive is not implemented)ex"); -} - -std::future Query::resolveExpensive(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getExpensive(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Query::getTestTaskState(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getTestTaskState is not implemented)ex"); -} - -std::future Query::resolveTestTaskState(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTestTaskState(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Query::getAnyType(service::FieldParams&&, std::vector&&) const -{ - throw std::runtime_error(R"ex(Query::getAnyType is not implemented)ex"); -} - -std::future Query::resolveAnyType(service::ResolverParams&& params) -{ - auto argIds = service::ModifiedArgument::require("ids", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getAnyType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIds)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Query::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Query)gql" }, std::move(params)); -} - -PageInfo::PageInfo() - : service::Object({ - "PageInfo" - }, { - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(hasNextPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasNextPage(std::move(params)); } }, - { R"gql(hasPreviousPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasPreviousPage(std::move(params)); } } - }) -{ -} - -service::FieldResult PageInfo::getHasNextPage(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(PageInfo::getHasNextPage is not implemented)ex"); -} - -std::future PageInfo::resolveHasNextPage(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHasNextPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult PageInfo::getHasPreviousPage(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(PageInfo::getHasPreviousPage is not implemented)ex"); -} - -std::future PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHasPreviousPage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future PageInfo::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(PageInfo)gql" }, std::move(params)); -} - -AppointmentEdge::AppointmentEdge() - : service::Object({ - "AppointmentEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> AppointmentEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentEdge::getNode is not implemented)ex"); -} - -std::future AppointmentEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult AppointmentEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentEdge::getCursor is not implemented)ex"); -} - -std::future AppointmentEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future AppointmentEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentEdge)gql" }, std::move(params)); -} - -AppointmentConnection::AppointmentConnection() - : service::Object({ - "AppointmentConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> AppointmentConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentConnection::getPageInfo is not implemented)ex"); -} - -std::future AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> AppointmentConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(AppointmentConnection::getEdges is not implemented)ex"); -} - -std::future AppointmentConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future AppointmentConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentConnection)gql" }, std::move(params)); -} - -TaskEdge::TaskEdge() - : service::Object({ - "TaskEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> TaskEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskEdge::getNode is not implemented)ex"); -} - -std::future TaskEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult TaskEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskEdge::getCursor is not implemented)ex"); -} - -std::future TaskEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future TaskEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(TaskEdge)gql" }, std::move(params)); -} - -TaskConnection::TaskConnection() - : service::Object({ - "TaskConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> TaskConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskConnection::getPageInfo is not implemented)ex"); -} - -std::future TaskConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> TaskConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(TaskConnection::getEdges is not implemented)ex"); -} - -std::future TaskConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future TaskConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(TaskConnection)gql" }, std::move(params)); -} - -FolderEdge::FolderEdge() - : service::Object({ - "FolderEdge" - }, { - { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, - { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> FolderEdge::getNode(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderEdge::getNode is not implemented)ex"); -} - -std::future FolderEdge::resolveNode(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNode(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult FolderEdge::getCursor(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderEdge::getCursor is not implemented)ex"); -} - -std::future FolderEdge::resolveCursor(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCursor(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future FolderEdge::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(FolderEdge)gql" }, std::move(params)); -} - -FolderConnection::FolderConnection() - : service::Object({ - "FolderConnection" - }, { - { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, - { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> FolderConnection::getPageInfo(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderConnection::getPageInfo is not implemented)ex"); -} - -std::future FolderConnection::resolvePageInfo(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPageInfo(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> FolderConnection::getEdges(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(FolderConnection::getEdges is not implemented)ex"); -} - -std::future FolderConnection::resolveEdges(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEdges(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future FolderConnection::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(FolderConnection)gql" }, std::move(params)); -} - -CompleteTaskPayload::CompleteTaskPayload() - : service::Object({ - "CompleteTaskPayload" - }, { - { R"gql(task)gql"sv, [this](service::ResolverParams&& params) { return resolveTask(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(clientMutationId)gql"sv, [this](service::ResolverParams&& params) { return resolveClientMutationId(std::move(params)); } } - }) -{ -} - -service::FieldResult> CompleteTaskPayload::getTask(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(CompleteTaskPayload::getTask is not implemented)ex"); -} - -std::future CompleteTaskPayload::resolveTask(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> CompleteTaskPayload::getClientMutationId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(CompleteTaskPayload::getClientMutationId is not implemented)ex"); -} - -std::future CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getClientMutationId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(CompleteTaskPayload)gql" }, std::move(params)); -} - -Mutation::Mutation() - : service::Object({ - "Mutation" - }, { - { R"gql(setFloat)gql"sv, [this](service::ResolverParams&& params) { return resolveSetFloat(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(completeTask)gql"sv, [this](service::ResolverParams&& params) { return resolveCompleteTask(std::move(params)); } } - }) -{ -} - -service::FieldResult> Mutation::applyCompleteTask(service::FieldParams&&, CompleteTaskInput&&) const -{ - throw std::runtime_error(R"ex(Mutation::applyCompleteTask is not implemented)ex"); -} - -std::future Mutation::resolveCompleteTask(service::ResolverParams&& params) -{ - auto argInput = service::ModifiedArgument::require("input", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = applyCompleteTask(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argInput)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Mutation::applySetFloat(service::FieldParams&&, response::FloatType&&) const -{ - throw std::runtime_error(R"ex(Mutation::applySetFloat is not implemented)ex"); -} - -std::future Mutation::resolveSetFloat(service::ResolverParams&& params) -{ - auto argValue = service::ModifiedArgument::require("value", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = applySetFloat(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argValue)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Mutation::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Mutation)gql" }, std::move(params)); -} - -Subscription::Subscription() - : service::Object({ - "Subscription" - }, { - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(nodeChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNodeChange(std::move(params)); } }, - { R"gql(nextAppointmentChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNextAppointmentChange(std::move(params)); } } - }) -{ -} - -service::FieldResult> Subscription::getNextAppointmentChange(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Subscription::getNextAppointmentChange is not implemented)ex"); -} - -std::future Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNextAppointmentChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Subscription::getNodeChange(service::FieldParams&&, response::IdType&&) const -{ - throw std::runtime_error(R"ex(Subscription::getNodeChange is not implemented)ex"); -} - -std::future Subscription::resolveNodeChange(service::ResolverParams&& params) -{ - auto argId = service::ModifiedArgument::require("id", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNodeChange(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argId)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Subscription::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Subscription)gql" }, std::move(params)); -} - -Appointment::Appointment() - : service::Object({ - "Node", - "UnionType", - "Appointment" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(when)gql"sv, [this](service::ResolverParams&& params) { return resolveWhen(std::move(params)); } }, - { R"gql(isNow)gql"sv, [this](service::ResolverParams&& params) { return resolveIsNow(std::move(params)); } }, - { R"gql(subject)gql"sv, [this](service::ResolverParams&& params) { return resolveSubject(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(forceError)gql"sv, [this](service::ResolverParams&& params) { return resolveForceError(std::move(params)); } } - }) -{ -} - -service::FieldResult Appointment::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); -} - -std::future Appointment::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getWhen(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getWhen is not implemented)ex"); -} - -std::future Appointment::resolveWhen(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getWhen(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getSubject(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getSubject is not implemented)ex"); -} - -std::future Appointment::resolveSubject(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getSubject(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Appointment::getIsNow(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getIsNow is not implemented)ex"); -} - -std::future Appointment::resolveIsNow(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getIsNow(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Appointment::getForceError(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Appointment::getForceError is not implemented)ex"); -} - -std::future Appointment::resolveForceError(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getForceError(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Appointment::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Appointment)gql" }, std::move(params)); -} - -Task::Task() - : service::Object({ - "Node", - "UnionType", - "Task" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(title)gql"sv, [this](service::ResolverParams&& params) { return resolveTitle(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(isComplete)gql"sv, [this](service::ResolverParams&& params) { return resolveIsComplete(std::move(params)); } } - }) -{ -} - -service::FieldResult Task::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Task::getId is not implemented)ex"); -} - -std::future Task::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Task::getTitle(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Task::getTitle is not implemented)ex"); -} - -std::future Task::resolveTitle(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTitle(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Task::getIsComplete(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Task::getIsComplete is not implemented)ex"); -} - -std::future Task::resolveIsComplete(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getIsComplete(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Task::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Task)gql" }, std::move(params)); -} - -Folder::Folder() - : service::Object({ - "Node", - "UnionType", - "Folder" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(unreadCount)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCount(std::move(params)); } } - }) -{ -} - -service::FieldResult Folder::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getId is not implemented)ex"); -} - -std::future Folder::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Folder::getName(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getName is not implemented)ex"); -} - -std::future Folder::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Folder::getUnreadCount(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Folder::getUnreadCount is not implemented)ex"); -} - -std::future Folder::resolveUnreadCount(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getUnreadCount(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Folder::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Folder)gql" }, std::move(params)); -} - -NestedType::NestedType() - : service::Object({ - "NestedType" - }, { - { R"gql(depth)gql"sv, [this](service::ResolverParams&& params) { return resolveDepth(std::move(params)); } }, - { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult NestedType::getDepth(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(NestedType::getDepth is not implemented)ex"); -} - -std::future NestedType::resolveDepth(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDepth(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> NestedType::getNested(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(NestedType::getNested is not implemented)ex"); -} - -std::future NestedType::resolveNested(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNested(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future NestedType::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(NestedType)gql" }, std::move(params)); -} - -Expensive::Expensive() - : service::Object({ - "Expensive" - }, { - { R"gql(order)gql"sv, [this](service::ResolverParams&& params) { return resolveOrder(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult Expensive::getOrder(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Expensive::getOrder is not implemented)ex"); -} - -std::future Expensive::resolveOrder(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getOrder(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Expensive::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Expensive)gql" }, std::move(params)); -} - -} // namespace object - -Operations::Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription) - : service::Request({ - { "query", query }, - { "mutation", mutation }, - { "subscription", subscription } - }, GetSchema()) - , _query(std::move(query)) - , _mutation(std::move(mutation)) - , _subscription(std::move(subscription)) -{ -} - -void AddTypesToSchema(const std::shared_ptr& schema) -{ - schema->AddType(R"gql(ItemCursor)gql"sv, schema::ScalarType::Make(R"gql(ItemCursor)gql"sv, R"md()md")); - schema->AddType(R"gql(DateTime)gql"sv, schema::ScalarType::Make(R"gql(DateTime)gql"sv, R"md()md")); - auto typeTaskState = schema::EnumType::Make(R"gql(TaskState)gql"sv, R"md()md"sv); - schema->AddType(R"gql(TaskState)gql"sv, typeTaskState); - auto typeCompleteTaskInput = schema::InputObjectType::Make(R"gql(CompleteTaskInput)gql"sv, R"md()md"sv); - schema->AddType(R"gql(CompleteTaskInput)gql"sv, typeCompleteTaskInput); - auto typeThirdNestedInput = schema::InputObjectType::Make(R"gql(ThirdNestedInput)gql"sv, R"md()md"sv); - schema->AddType(R"gql(ThirdNestedInput)gql"sv, typeThirdNestedInput); - auto typeFourthNestedInput = schema::InputObjectType::Make(R"gql(FourthNestedInput)gql"sv, R"md()md"sv); - schema->AddType(R"gql(FourthNestedInput)gql"sv, typeFourthNestedInput); - auto typeSecondNestedInput = schema::InputObjectType::Make(R"gql(SecondNestedInput)gql"sv, R"md()md"sv); - schema->AddType(R"gql(SecondNestedInput)gql"sv, typeSecondNestedInput); - auto typeFirstNestedInput = schema::InputObjectType::Make(R"gql(FirstNestedInput)gql"sv, R"md()md"sv); - schema->AddType(R"gql(FirstNestedInput)gql"sv, typeFirstNestedInput); - auto typeUnionType = schema::UnionType::Make(R"gql(UnionType)gql"sv, R"md()md"sv); - schema->AddType(R"gql(UnionType)gql"sv, typeUnionType); - auto typeNode = schema::InterfaceType::Make(R"gql(Node)gql"sv, R"md()md"sv); - schema->AddType(R"gql(Node)gql"sv, typeNode); - auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md()md"); - schema->AddType(R"gql(Query)gql"sv, typeQuery); - auto typePageInfo = schema::ObjectType::Make(R"gql(PageInfo)gql"sv, R"md()md"); - schema->AddType(R"gql(PageInfo)gql"sv, typePageInfo); - auto typeAppointmentEdge = schema::ObjectType::Make(R"gql(AppointmentEdge)gql"sv, R"md()md"); - schema->AddType(R"gql(AppointmentEdge)gql"sv, typeAppointmentEdge); - auto typeAppointmentConnection = schema::ObjectType::Make(R"gql(AppointmentConnection)gql"sv, R"md()md"); - schema->AddType(R"gql(AppointmentConnection)gql"sv, typeAppointmentConnection); - auto typeTaskEdge = schema::ObjectType::Make(R"gql(TaskEdge)gql"sv, R"md()md"); - schema->AddType(R"gql(TaskEdge)gql"sv, typeTaskEdge); - auto typeTaskConnection = schema::ObjectType::Make(R"gql(TaskConnection)gql"sv, R"md()md"); - schema->AddType(R"gql(TaskConnection)gql"sv, typeTaskConnection); - auto typeFolderEdge = schema::ObjectType::Make(R"gql(FolderEdge)gql"sv, R"md()md"); - schema->AddType(R"gql(FolderEdge)gql"sv, typeFolderEdge); - auto typeFolderConnection = schema::ObjectType::Make(R"gql(FolderConnection)gql"sv, R"md()md"); - schema->AddType(R"gql(FolderConnection)gql"sv, typeFolderConnection); - auto typeCompleteTaskPayload = schema::ObjectType::Make(R"gql(CompleteTaskPayload)gql"sv, R"md()md"); - schema->AddType(R"gql(CompleteTaskPayload)gql"sv, typeCompleteTaskPayload); - auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"); - schema->AddType(R"gql(Mutation)gql"sv, typeMutation); - auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"); - schema->AddType(R"gql(Subscription)gql"sv, typeSubscription); - auto typeAppointment = schema::ObjectType::Make(R"gql(Appointment)gql"sv, R"md()md"); - schema->AddType(R"gql(Appointment)gql"sv, typeAppointment); - auto typeTask = schema::ObjectType::Make(R"gql(Task)gql"sv, R"md()md"); - schema->AddType(R"gql(Task)gql"sv, typeTask); - auto typeFolder = schema::ObjectType::Make(R"gql(Folder)gql"sv, R"md()md"); - schema->AddType(R"gql(Folder)gql"sv, typeFolder); - auto typeNestedType = schema::ObjectType::Make(R"gql(NestedType)gql"sv, R"md()md"); - schema->AddType(R"gql(NestedType)gql"sv, typeNestedType); - auto typeExpensive = schema::ObjectType::Make(R"gql(Expensive)gql"sv, R"md()md"); - schema->AddType(R"gql(Expensive)gql"sv, typeExpensive); - - typeTaskState->AddEnumValues({ - { service::s_namesTaskState[static_cast(today::TaskState::New)], R"md()md"sv, std::nullopt }, - { service::s_namesTaskState[static_cast(today::TaskState::Started)], R"md()md"sv, std::nullopt }, - { service::s_namesTaskState[static_cast(today::TaskState::Complete)], R"md()md"sv, std::nullopt }, - { service::s_namesTaskState[static_cast(today::TaskState::Unassigned)], R"md()md"sv, std::make_optional(R"md(Need to deprecate an [enum value](http://spec.graphql.org/June2018/#sec-Deprecation))md"sv) } - }); - - typeCompleteTaskInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, schema->LookupType("TaskState"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(isComplete)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(true)gql"sv), - schema::InputValue::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) - }); - typeThirdNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) - }); - typeFourthNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) - }); - typeSecondNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ThirdNestedInput")), R"gql()gql"sv) - }); - typeFirstNestedInput->AddInputValues({ - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(second)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("SecondNestedInput")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(third)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ThirdNestedInput")), R"gql()gql"sv) - }); - - typeUnionType->AddPossibleTypes({ - schema->LookupType(R"gql(Appointment)gql"sv), - schema->LookupType(R"gql(Task)gql"sv), - schema->LookupType(R"gql(Folder)gql"sv) - }); - - typeNode->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) - }); - - typeQuery->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Node"), { - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(appointments)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("AppointmentConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(tasks)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(unreadCounts)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("FolderConnection")), { - schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(appointmentsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Appointment"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql"sv) - }), - schema::Field::Make(R"gql(tasksById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Task"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(unreadCountsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Folder"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))), - schema::Field::Make(R"gql(unimplemented)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(expensive)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Expensive"))))), - schema::Field::Make(R"gql(testTaskState)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskState"))), - schema::Field::Make(R"gql(anyType)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("UnionType"))), { - schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) - }) - }); - typePageInfo->AddFields({ - schema::Field::Make(R"gql(hasNextPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - schema::Field::Make(R"gql(hasPreviousPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) - }); - typeAppointmentEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Appointment")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); - typeAppointmentConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))) - }); - typeTaskEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); - typeTaskConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))) - }); - typeFolderEdge->AddFields({ - schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Folder")), - schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) - }); - typeFolderConnection->AddFields({ - schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))) - }); - typeCompleteTaskPayload->AddFields({ - schema::Field::Make(R"gql(task)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), - schema::Field::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); - typeMutation->AddFields({ - schema::Field::Make(R"gql(completeTask)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskPayload")), { - schema::InputValue::Make(R"gql(input)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskInput")), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(setFloat)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), { - schema::InputValue::Make(R"gql(value)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), R"gql()gql"sv) - }) - }); - typeSubscription->AddFields({ - schema::Field::Make(R"gql(nextAppointmentChange)gql"sv, R"md()md"sv, std::make_optional(R"md(Need to deprecate a [field](http://spec.graphql.org/June2018/#sec-Deprecation))md"sv), schema->LookupType("Appointment")), - schema::Field::Make(R"gql(nodeChange)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Node")), { - schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) - }) - }); - typeAppointment->AddInterfaces({ - typeNode - }); - typeAppointment->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(when)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("DateTime")), - schema::Field::Make(R"gql(subject)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(isNow)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - schema::Field::Make(R"gql(forceError)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); - typeTask->AddInterfaces({ - typeNode - }); - typeTask->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(title)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(isComplete)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) - }); - typeFolder->AddInterfaces({ - typeNode - }); - typeFolder->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(unreadCount)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) - }); - typeNestedType->AddFields({ - schema::Field::Make(R"gql(depth)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), - schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))) - }); - typeExpensive->AddFields({ - schema::Field::Make(R"gql(order)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) - }); - - schema->AddDirective(schema::Directive::Make(R"gql(id)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::FIELD_DEFINITION - })); - schema->AddDirective(schema::Directive::Make(R"gql(subscriptionTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::SUBSCRIPTION - }, { - schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(queryTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::QUERY - }, { - schema::InputValue::Make(R"gql(query)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(fieldTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::FIELD - }, { - schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(fragmentDefinitionTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::FRAGMENT_DEFINITION - }, { - schema::InputValue::Make(R"gql(fragmentDefinition)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(fragmentSpreadTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::FRAGMENT_SPREAD - }, { - schema::InputValue::Make(R"gql(fragmentSpread)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(inlineFragmentTag)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::INLINE_FRAGMENT - }, { - schema::InputValue::Make(R"gql(inlineFragment)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) - })); - - schema->AddQueryType(typeQuery); - schema->AddMutationType(typeMutation); - schema->AddSubscriptionType(typeSubscription); -} - -std::shared_ptr GetSchema() -{ - static std::weak_ptr s_wpSchema; - auto schema = s_wpSchema.lock(); - - if (!schema) - { - schema = std::make_shared(true); - introspection::AddTypesToSchema(schema); - AddTypesToSchema(schema); - s_wpSchema = schema; - } - - return schema; -} - -} // namespace today -} // namespace graphql diff --git a/samples/unified_nointrospection/TodaySchema.h b/samples/unified_nointrospection/TodaySchema.h deleted file mode 100644 index cd45ef6e..00000000 --- a/samples/unified_nointrospection/TodaySchema.h +++ /dev/null @@ -1,413 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef TODAYSCHEMA_H -#define TODAYSCHEMA_H - -#include "graphqlservice/internal/Schema.h" - -// Check if the library version is compatible with schemagen 3.6.0 -static_assert(graphql::internal::MajorVersion == 3, "regenerate with schemagen: major version mismatch"); -static_assert(graphql::internal::MinorVersion == 6, "regenerate with schemagen: minor version mismatch"); - -#include -#include -#include - -namespace graphql { -namespace today { - -enum class TaskState -{ - New, - Started, - Complete, - Unassigned -}; - -struct CompleteTaskInput -{ - response::IdType id; - std::optional testTaskState; - std::optional isComplete; - std::optional clientMutationId; -}; - -struct ThirdNestedInput -{ - response::IdType id; -}; - -struct FourthNestedInput -{ - response::IdType id; -}; - -struct SecondNestedInput -{ - response::IdType id; - ThirdNestedInput third; -}; - -struct FirstNestedInput -{ - response::IdType id; - SecondNestedInput second; - ThirdNestedInput third; -}; - -namespace object { - -class Query; -class PageInfo; -class AppointmentEdge; -class AppointmentConnection; -class TaskEdge; -class TaskConnection; -class FolderEdge; -class FolderConnection; -class CompleteTaskPayload; -class Mutation; -class Subscription; -class Appointment; -class Task; -class Folder; -class NestedType; -class Expensive; - -} // namespace object - -struct Node -{ - virtual service::FieldResult getId(service::FieldParams&& params) const = 0; -}; - -namespace object { - -class Query - : public service::Object -{ -protected: - explicit Query(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params, response::IdType&& idArg) const; - virtual service::FieldResult> getAppointments(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult> getTasks(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult> getUnreadCounts(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; - virtual service::FieldResult>> getAppointmentsById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult>> getTasksById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult>> getUnreadCountsById(service::FieldParams&& params, std::vector&& idsArg) const; - virtual service::FieldResult> getNested(service::FieldParams&& params) const; - virtual service::FieldResult getUnimplemented(service::FieldParams&& params) const; - virtual service::FieldResult>> getExpensive(service::FieldParams&& params) const; - virtual service::FieldResult getTestTaskState(service::FieldParams&& params) const; - virtual service::FieldResult>> getAnyType(service::FieldParams&& params, std::vector&& idsArg) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveAppointments(service::ResolverParams&& params); - std::future resolveTasks(service::ResolverParams&& params); - std::future resolveUnreadCounts(service::ResolverParams&& params); - std::future resolveAppointmentsById(service::ResolverParams&& params); - std::future resolveTasksById(service::ResolverParams&& params); - std::future resolveUnreadCountsById(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); - std::future resolveUnimplemented(service::ResolverParams&& params); - std::future resolveExpensive(service::ResolverParams&& params); - std::future resolveTestTaskState(service::ResolverParams&& params); - std::future resolveAnyType(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class PageInfo - : public service::Object -{ -protected: - explicit PageInfo(); - -public: - virtual service::FieldResult getHasNextPage(service::FieldParams&& params) const; - virtual service::FieldResult getHasPreviousPage(service::FieldParams&& params) const; - -private: - std::future resolveHasNextPage(service::ResolverParams&& params); - std::future resolveHasPreviousPage(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class AppointmentEdge - : public service::Object -{ -protected: - explicit AppointmentEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class AppointmentConnection - : public service::Object -{ -protected: - explicit AppointmentConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class TaskEdge - : public service::Object -{ -protected: - explicit TaskEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class TaskConnection - : public service::Object -{ -protected: - explicit TaskConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class FolderEdge - : public service::Object -{ -protected: - explicit FolderEdge(); - -public: - virtual service::FieldResult> getNode(service::FieldParams&& params) const; - virtual service::FieldResult getCursor(service::FieldParams&& params) const; - -private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class FolderConnection - : public service::Object -{ -protected: - explicit FolderConnection(); - -public: - virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; - virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; - -private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class CompleteTaskPayload - : public service::Object -{ -protected: - explicit CompleteTaskPayload(); - -public: - virtual service::FieldResult> getTask(service::FieldParams&& params) const; - virtual service::FieldResult> getClientMutationId(service::FieldParams&& params) const; - -private: - std::future resolveTask(service::ResolverParams&& params); - std::future resolveClientMutationId(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Mutation - : public service::Object -{ -protected: - explicit Mutation(); - -public: - virtual service::FieldResult> applyCompleteTask(service::FieldParams&& params, CompleteTaskInput&& inputArg) const; - virtual service::FieldResult applySetFloat(service::FieldParams&& params, response::FloatType&& valueArg) const; - -private: - std::future resolveCompleteTask(service::ResolverParams&& params); - std::future resolveSetFloat(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Subscription - : public service::Object -{ -protected: - explicit Subscription(); - -public: - virtual service::FieldResult> getNextAppointmentChange(service::FieldParams&& params) const; - virtual service::FieldResult> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const; - -private: - std::future resolveNextAppointmentChange(service::ResolverParams&& params); - std::future resolveNodeChange(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Appointment - : public service::Object - , public Node -{ -protected: - explicit Appointment(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getWhen(service::FieldParams&& params) const; - virtual service::FieldResult> getSubject(service::FieldParams&& params) const; - virtual service::FieldResult getIsNow(service::FieldParams&& params) const; - virtual service::FieldResult> getForceError(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveWhen(service::ResolverParams&& params); - std::future resolveSubject(service::ResolverParams&& params); - std::future resolveIsNow(service::ResolverParams&& params); - std::future resolveForceError(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Task - : public service::Object - , public Node -{ -protected: - explicit Task(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getTitle(service::FieldParams&& params) const; - virtual service::FieldResult getIsComplete(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveTitle(service::ResolverParams&& params); - std::future resolveIsComplete(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Folder - : public service::Object - , public Node -{ -protected: - explicit Folder(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const override; - virtual service::FieldResult> getName(service::FieldParams&& params) const; - virtual service::FieldResult getUnreadCount(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveName(service::ResolverParams&& params); - std::future resolveUnreadCount(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class NestedType - : public service::Object -{ -protected: - explicit NestedType(); - -public: - virtual service::FieldResult getDepth(service::FieldParams&& params) const; - virtual service::FieldResult> getNested(service::FieldParams&& params) const; - -private: - std::future resolveDepth(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Expensive - : public service::Object -{ -protected: - explicit Expensive(); - -public: - virtual service::FieldResult getOrder(service::FieldParams&& params) const; - -private: - std::future resolveOrder(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace object - -class Operations - : public service::Request -{ -public: - explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription); - -private: - std::shared_ptr _query; - std::shared_ptr _mutation; - std::shared_ptr _subscription; -}; - -std::shared_ptr GetSchema(); - -} // namespace today -} // namespace graphql - -#endif // TODAYSCHEMA_H diff --git a/samples/update_samples.cmake b/samples/update_samples.cmake deleted file mode 100644 index 1d3d2757..00000000 --- a/samples/update_samples.cmake +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -cmake_minimum_required(VERSION 3.8.2) - -# Get the up-to-date list of files in the binary directory -set(FILE_NAMES "") -file(GLOB NEW_FILES ${SCHEMA_BINARY_DIR}/*.h ${SCHEMA_BINARY_DIR}/*.cpp) -foreach(NEW_FILE ${NEW_FILES}) - get_filename_component(NEW_FILE ${NEW_FILE} NAME) - list(APPEND FILE_NAMES "${NEW_FILE}") -endforeach() - -# Don't update the files in the source directory if no files were generated in the binary directory. -if(NOT FILE_NAMES) - message(FATAL_ERROR "Schema generation failed!") -endif() - -# Remove stale files in the source directory -file(GLOB OLD_FILES ${SCHEMA_SOURCE_DIR}/*.h ${SCHEMA_SOURCE_DIR}/*.cpp) -foreach(OLD_FILE ${OLD_FILES}) - get_filename_component(OLD_FILE ${OLD_FILE} NAME) - if(NOT OLD_FILE IN_LIST FILE_NAMES) - file(REMOVE "${SCHEMA_SOURCE_DIR}/${OLD_FILE}") - endif() -endforeach() - -# Copy new and modified files from the binary directory to the source directory -execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SCHEMA_BINARY_DIR}/${SCHEMA_SOURCE_LIST} ${NEW_FILES} ${SCHEMA_SOURCE_DIR}) diff --git a/samples/validation/CMakeLists.txt b/samples/validation/CMakeLists.txt new file mode 100644 index 00000000..8db4b408 --- /dev/null +++ b/samples/validation/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +if(GRAPHQL_BUILD_TESTS) + add_subdirectory(schema) + add_library(validationgraphql STATIC + ValidationMock.cpp) + target_link_libraries(validationgraphql PUBLIC validation_schema) + target_include_directories(validationgraphql PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + add_bigobj_flag(validationgraphql) +endif() diff --git a/samples/validation/ValidationMock.h b/samples/validation/ValidationMock.h index 4cb47be2..8c079aab 100644 --- a/samples/validation/ValidationMock.h +++ b/samples/validation/ValidationMock.h @@ -8,21 +8,25 @@ #include "ValidationSchema.h" +#include "QueryObject.h" +#include "MutationObject.h" +#include "SubscriptionObject.h" + namespace graphql::validation { -class Query : public object::Query +class Query { public: explicit Query() = default; }; -class Mutation : public object::Mutation +class Mutation { public: explicit Mutation() = default; }; -class Subscription : public object::Subscription +class Subscription { public: explicit Subscription() = default; diff --git a/samples/validation/ValidationSchema.cpp b/samples/validation/ValidationSchema.cpp deleted file mode 100644 index c4d0fed0..00000000 --- a/samples/validation/ValidationSchema.cpp +++ /dev/null @@ -1,1074 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "ValidationSchema.h" - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql { -namespace service { - -static const std::array s_namesDogCommand = { - "SIT"sv, - "DOWN"sv, - "HEEL"sv -}; - -template <> -validation::DogCommand ModifiedArgument::convert(const response::Value& value) -{ - if (!value.maybe_enum()) - { - throw service::schema_exception { { "not a valid DogCommand value" } }; - } - - const auto itr = std::find(s_namesDogCommand.cbegin(), s_namesDogCommand.cend(), value.get()); - - if (itr == s_namesDogCommand.cend()) - { - throw service::schema_exception { { "not a valid DogCommand value" } }; - } - - return static_cast(itr - s_namesDogCommand.cbegin()); -} - -template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) -{ - return resolve(std::move(result), std::move(params), - [](validation::DogCommand value, const ResolverParams&) - { - response::Value result(response::Type::EnumValue); - - result.set(response::StringType { s_namesDogCommand[static_cast(value)] }); - - return result; - }); -} - -static const std::array s_namesCatCommand = { - "JUMP"sv -}; - -template <> -validation::CatCommand ModifiedArgument::convert(const response::Value& value) -{ - if (!value.maybe_enum()) - { - throw service::schema_exception { { "not a valid CatCommand value" } }; - } - - const auto itr = std::find(s_namesCatCommand.cbegin(), s_namesCatCommand.cend(), value.get()); - - if (itr == s_namesCatCommand.cend()) - { - throw service::schema_exception { { "not a valid CatCommand value" } }; - } - - return static_cast(itr - s_namesCatCommand.cbegin()); -} - -template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) -{ - return resolve(std::move(result), std::move(params), - [](validation::CatCommand value, const ResolverParams&) - { - response::Value result(response::Type::EnumValue); - - result.set(response::StringType { s_namesCatCommand[static_cast(value)] }); - - return result; - }); -} - -template <> -validation::ComplexInput ModifiedArgument::convert(const response::Value& value) -{ - auto valueName = service::ModifiedArgument::require("name", value); - auto valueOwner = service::ModifiedArgument::require("owner", value); - - return { - std::move(valueName), - std::move(valueOwner) - }; -} - -} // namespace service - -namespace validation { -namespace object { - -Query::Query() - : service::Object({ - "Query" - }, { - { R"gql(dog)gql"sv, [this](service::ResolverParams&& params) { return resolveDog(std::move(params)); } }, - { R"gql(pet)gql"sv, [this](service::ResolverParams&& params) { return resolvePet(std::move(params)); } }, - { R"gql(human)gql"sv, [this](service::ResolverParams&& params) { return resolveHuman(std::move(params)); } }, - { R"gql(__type)gql"sv, [this](service::ResolverParams&& params) { return resolve_type(std::move(params)); } }, - { R"gql(findDog)gql"sv, [this](service::ResolverParams&& params) { return resolveFindDog(std::move(params)); } }, - { R"gql(__schema)gql"sv, [this](service::ResolverParams&& params) { return resolve_schema(std::move(params)); } }, - { R"gql(catOrDog)gql"sv, [this](service::ResolverParams&& params) { return resolveCatOrDog(std::move(params)); } }, - { R"gql(arguments)gql"sv, [this](service::ResolverParams&& params) { return resolveArguments(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(booleanList)gql"sv, [this](service::ResolverParams&& params) { return resolveBooleanList(std::move(params)); } } - }) - , _schema(GetSchema()) -{ -} - -service::FieldResult> Query::getDog(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getDog is not implemented)ex"); -} - -std::future Query::resolveDog(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDog(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getHuman(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getHuman is not implemented)ex"); -} - -std::future Query::resolveHuman(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHuman(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getPet(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getPet is not implemented)ex"); -} - -std::future Query::resolvePet(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPet(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getCatOrDog(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getCatOrDog is not implemented)ex"); -} - -std::future Query::resolveCatOrDog(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getCatOrDog(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getArguments(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Query::getArguments is not implemented)ex"); -} - -std::future Query::resolveArguments(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getArguments(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getFindDog(service::FieldParams&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Query::getFindDog is not implemented)ex"); -} - -std::future Query::resolveFindDog(service::ResolverParams&& params) -{ - auto argComplex = service::ModifiedArgument::require("complex", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getFindDog(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argComplex)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Query::getBooleanList(service::FieldParams&&, std::optional>&&) const -{ - throw std::runtime_error(R"ex(Query::getBooleanList is not implemented)ex"); -} - -std::future Query::resolveBooleanList(service::ResolverParams&& params) -{ - auto argBooleanListArg = service::ModifiedArgument::require("booleanListArg", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getBooleanList(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argBooleanListArg)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Query::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Query)gql" }, std::move(params)); -} - -std::future Query::resolve_schema(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(std::static_pointer_cast(std::make_shared(_schema)), std::move(params)); -} - -std::future Query::resolve_type(service::ResolverParams&& params) -{ - auto argName = service::ModifiedArgument::require("name", params.arguments); - const auto& baseType = _schema->LookupType(argName); - std::shared_ptr result { baseType ? std::make_shared(baseType) : nullptr }; - - return service::ModifiedResult::convert(result, std::move(params)); -} - -Dog::Dog() - : service::Object({ - "Pet", - "CatOrDog", - "DogOrHuman", - "Dog" - }, { - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(owner)gql"sv, [this](service::ResolverParams&& params) { return resolveOwner(std::move(params)); } }, - { R"gql(nickname)gql"sv, [this](service::ResolverParams&& params) { return resolveNickname(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(barkVolume)gql"sv, [this](service::ResolverParams&& params) { return resolveBarkVolume(std::move(params)); } }, - { R"gql(isHousetrained)gql"sv, [this](service::ResolverParams&& params) { return resolveIsHousetrained(std::move(params)); } }, - { R"gql(doesKnowCommand)gql"sv, [this](service::ResolverParams&& params) { return resolveDoesKnowCommand(std::move(params)); } } - }) -{ -} - -service::FieldResult Dog::getName(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Dog::getName is not implemented)ex"); -} - -std::future Dog::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Dog::getNickname(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Dog::getNickname is not implemented)ex"); -} - -std::future Dog::resolveNickname(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNickname(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Dog::getBarkVolume(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Dog::getBarkVolume is not implemented)ex"); -} - -std::future Dog::resolveBarkVolume(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getBarkVolume(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Dog::getDoesKnowCommand(service::FieldParams&&, DogCommand&&) const -{ - throw std::runtime_error(R"ex(Dog::getDoesKnowCommand is not implemented)ex"); -} - -std::future Dog::resolveDoesKnowCommand(service::ResolverParams&& params) -{ - auto argDogCommand = service::ModifiedArgument::require("dogCommand", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDoesKnowCommand(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argDogCommand)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Dog::getIsHousetrained(service::FieldParams&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Dog::getIsHousetrained is not implemented)ex"); -} - -std::future Dog::resolveIsHousetrained(service::ResolverParams&& params) -{ - auto argAtOtherHomes = service::ModifiedArgument::require("atOtherHomes", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getIsHousetrained(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argAtOtherHomes)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Dog::getOwner(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Dog::getOwner is not implemented)ex"); -} - -std::future Dog::resolveOwner(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getOwner(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Dog::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Dog)gql" }, std::move(params)); -} - -Alien::Alien() - : service::Object({ - "Sentient", - "HumanOrAlien", - "Alien" - }, { - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(homePlanet)gql"sv, [this](service::ResolverParams&& params) { return resolveHomePlanet(std::move(params)); } } - }) -{ -} - -service::FieldResult Alien::getName(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Alien::getName is not implemented)ex"); -} - -std::future Alien::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Alien::getHomePlanet(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Alien::getHomePlanet is not implemented)ex"); -} - -std::future Alien::resolveHomePlanet(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getHomePlanet(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Alien::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Alien)gql" }, std::move(params)); -} - -Human::Human() - : service::Object({ - "Sentient", - "DogOrHuman", - "HumanOrAlien", - "Human" - }, { - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(pets)gql"sv, [this](service::ResolverParams&& params) { return resolvePets(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult Human::getName(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Human::getName is not implemented)ex"); -} - -std::future Human::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Human::getPets(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Human::getPets is not implemented)ex"); -} - -std::future Human::resolvePets(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPets(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Human::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Human)gql" }, std::move(params)); -} - -Cat::Cat() - : service::Object({ - "Pet", - "CatOrDog", - "Cat" - }, { - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(nickname)gql"sv, [this](service::ResolverParams&& params) { return resolveNickname(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(meowVolume)gql"sv, [this](service::ResolverParams&& params) { return resolveMeowVolume(std::move(params)); } }, - { R"gql(doesKnowCommand)gql"sv, [this](service::ResolverParams&& params) { return resolveDoesKnowCommand(std::move(params)); } } - }) -{ -} - -service::FieldResult Cat::getName(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Cat::getName is not implemented)ex"); -} - -std::future Cat::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Cat::getNickname(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Cat::getNickname is not implemented)ex"); -} - -std::future Cat::resolveNickname(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNickname(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Cat::getDoesKnowCommand(service::FieldParams&&, CatCommand&&) const -{ - throw std::runtime_error(R"ex(Cat::getDoesKnowCommand is not implemented)ex"); -} - -std::future Cat::resolveDoesKnowCommand(service::ResolverParams&& params) -{ - auto argCatCommand = service::ModifiedArgument::require("catCommand", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDoesKnowCommand(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argCatCommand)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Cat::getMeowVolume(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Cat::getMeowVolume is not implemented)ex"); -} - -std::future Cat::resolveMeowVolume(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getMeowVolume(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Cat::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Cat)gql" }, std::move(params)); -} - -Mutation::Mutation() - : service::Object({ - "Mutation" - }, { - { R"gql(mutateDog)gql"sv, [this](service::ResolverParams&& params) { return resolveMutateDog(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> Mutation::applyMutateDog(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Mutation::applyMutateDog is not implemented)ex"); -} - -std::future Mutation::resolveMutateDog(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = applyMutateDog(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Mutation::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Mutation)gql" }, std::move(params)); -} - -MutateDogResult::MutateDogResult() - : service::Object({ - "MutateDogResult" - }, { - { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult MutateDogResult::getId(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(MutateDogResult::getId is not implemented)ex"); -} - -std::future MutateDogResult::resolveId(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future MutateDogResult::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(MutateDogResult)gql" }, std::move(params)); -} - -Subscription::Subscription() - : service::Object({ - "Subscription" - }, { - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(newMessage)gql"sv, [this](service::ResolverParams&& params) { return resolveNewMessage(std::move(params)); } }, - { R"gql(disallowedSecondRootField)gql"sv, [this](service::ResolverParams&& params) { return resolveDisallowedSecondRootField(std::move(params)); } } - }) -{ -} - -service::FieldResult> Subscription::getNewMessage(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Subscription::getNewMessage is not implemented)ex"); -} - -std::future Subscription::resolveNewMessage(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNewMessage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Subscription::getDisallowedSecondRootField(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Subscription::getDisallowedSecondRootField is not implemented)ex"); -} - -std::future Subscription::resolveDisallowedSecondRootField(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDisallowedSecondRootField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Subscription::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Subscription)gql" }, std::move(params)); -} - -Message::Message() - : service::Object({ - "Message" - }, { - { R"gql(body)gql"sv, [this](service::ResolverParams&& params) { return resolveBody(std::move(params)); } }, - { R"gql(sender)gql"sv, [this](service::ResolverParams&& params) { return resolveSender(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } - }) -{ -} - -service::FieldResult> Message::getBody(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Message::getBody is not implemented)ex"); -} - -std::future Message::resolveBody(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getBody(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Message::getSender(service::FieldParams&&) const -{ - throw std::runtime_error(R"ex(Message::getSender is not implemented)ex"); -} - -std::future Message::resolveSender(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getSender(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Message::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Message)gql" }, std::move(params)); -} - -Arguments::Arguments() - : service::Object({ - "Arguments" - }, { - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(intArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveIntArgField(std::move(params)); } }, - { R"gql(multipleReqs)gql"sv, [this](service::ResolverParams&& params) { return resolveMultipleReqs(std::move(params)); } }, - { R"gql(floatArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveFloatArgField(std::move(params)); } }, - { R"gql(booleanArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveBooleanArgField(std::move(params)); } }, - { R"gql(booleanListArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveBooleanListArgField(std::move(params)); } }, - { R"gql(nonNullBooleanArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveNonNullBooleanArgField(std::move(params)); } }, - { R"gql(nonNullBooleanListField)gql"sv, [this](service::ResolverParams&& params) { return resolveNonNullBooleanListField(std::move(params)); } }, - { R"gql(optionalNonNullBooleanArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveOptionalNonNullBooleanArgField(std::move(params)); } } - }) -{ -} - -service::FieldResult Arguments::getMultipleReqs(service::FieldParams&&, response::IntType&&, response::IntType&&) const -{ - throw std::runtime_error(R"ex(Arguments::getMultipleReqs is not implemented)ex"); -} - -std::future Arguments::resolveMultipleReqs(service::ResolverParams&& params) -{ - auto argX = service::ModifiedArgument::require("x", params.arguments); - auto argY = service::ModifiedArgument::require("y", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getMultipleReqs(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argX), std::move(argY)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Arguments::getBooleanArgField(service::FieldParams&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Arguments::getBooleanArgField is not implemented)ex"); -} - -std::future Arguments::resolveBooleanArgField(service::ResolverParams&& params) -{ - auto argBooleanArg = service::ModifiedArgument::require("booleanArg", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getBooleanArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argBooleanArg)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Arguments::getFloatArgField(service::FieldParams&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Arguments::getFloatArgField is not implemented)ex"); -} - -std::future Arguments::resolveFloatArgField(service::ResolverParams&& params) -{ - auto argFloatArg = service::ModifiedArgument::require("floatArg", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getFloatArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFloatArg)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult> Arguments::getIntArgField(service::FieldParams&&, std::optional&&) const -{ - throw std::runtime_error(R"ex(Arguments::getIntArgField is not implemented)ex"); -} - -std::future Arguments::resolveIntArgField(service::ResolverParams&& params) -{ - auto argIntArg = service::ModifiedArgument::require("intArg", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getIntArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIntArg)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Arguments::getNonNullBooleanArgField(service::FieldParams&&, response::BooleanType&&) const -{ - throw std::runtime_error(R"ex(Arguments::getNonNullBooleanArgField is not implemented)ex"); -} - -std::future Arguments::resolveNonNullBooleanArgField(service::ResolverParams&& params) -{ - auto argNonNullBooleanArg = service::ModifiedArgument::require("nonNullBooleanArg", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNonNullBooleanArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argNonNullBooleanArg)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>> Arguments::getNonNullBooleanListField(service::FieldParams&&, std::optional>&&) const -{ - throw std::runtime_error(R"ex(Arguments::getNonNullBooleanListField is not implemented)ex"); -} - -std::future Arguments::resolveNonNullBooleanListField(service::ResolverParams&& params) -{ - auto argNonNullBooleanListArg = service::ModifiedArgument::require("nonNullBooleanListArg", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getNonNullBooleanListField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argNonNullBooleanListArg)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult>>> Arguments::getBooleanListArgField(service::FieldParams&&, std::vector>&&) const -{ - throw std::runtime_error(R"ex(Arguments::getBooleanListArgField is not implemented)ex"); -} - -std::future Arguments::resolveBooleanListArgField(service::ResolverParams&& params) -{ - auto argBooleanListArg = service::ModifiedArgument::require("booleanListArg", params.arguments); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getBooleanListArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argBooleanListArg)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -service::FieldResult Arguments::getOptionalNonNullBooleanArgField(service::FieldParams&&, response::BooleanType&&) const -{ - throw std::runtime_error(R"ex(Arguments::getOptionalNonNullBooleanArgField is not implemented)ex"); -} - -std::future Arguments::resolveOptionalNonNullBooleanArgField(service::ResolverParams&& params) -{ - const auto defaultArguments = []() - { - response::Value values(response::Type::Map); - response::Value entry; - - entry = response::Value(false); - values.emplace_back("optionalBooleanArg", std::move(entry)); - - return values; - }(); - - auto pairOptionalBooleanArg = service::ModifiedArgument::find("optionalBooleanArg", params.arguments); - auto argOptionalBooleanArg = (pairOptionalBooleanArg.second - ? std::move(pairOptionalBooleanArg.first) - : service::ModifiedArgument::require("optionalBooleanArg", defaultArguments)); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getOptionalNonNullBooleanArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argOptionalBooleanArg)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Arguments::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(Arguments)gql" }, std::move(params)); -} - -} // namespace object - -Operations::Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription) - : service::Request({ - { "query", query }, - { "mutation", mutation }, - { "subscription", subscription } - }, GetSchema()) - , _query(std::move(query)) - , _mutation(std::move(mutation)) - , _subscription(std::move(subscription)) -{ -} - -void AddTypesToSchema(const std::shared_ptr& schema) -{ - auto typeDogCommand = schema::EnumType::Make(R"gql(DogCommand)gql"sv, R"md()md"sv); - schema->AddType(R"gql(DogCommand)gql"sv, typeDogCommand); - auto typeCatCommand = schema::EnumType::Make(R"gql(CatCommand)gql"sv, R"md()md"sv); - schema->AddType(R"gql(CatCommand)gql"sv, typeCatCommand); - auto typeComplexInput = schema::InputObjectType::Make(R"gql(ComplexInput)gql"sv, R"md([Example 155](http://spec.graphql.org/June2018/#example-f3185))md"sv); - schema->AddType(R"gql(ComplexInput)gql"sv, typeComplexInput); - auto typeCatOrDog = schema::UnionType::Make(R"gql(CatOrDog)gql"sv, R"md()md"sv); - schema->AddType(R"gql(CatOrDog)gql"sv, typeCatOrDog); - auto typeDogOrHuman = schema::UnionType::Make(R"gql(DogOrHuman)gql"sv, R"md()md"sv); - schema->AddType(R"gql(DogOrHuman)gql"sv, typeDogOrHuman); - auto typeHumanOrAlien = schema::UnionType::Make(R"gql(HumanOrAlien)gql"sv, R"md()md"sv); - schema->AddType(R"gql(HumanOrAlien)gql"sv, typeHumanOrAlien); - auto typeSentient = schema::InterfaceType::Make(R"gql(Sentient)gql"sv, R"md()md"sv); - schema->AddType(R"gql(Sentient)gql"sv, typeSentient); - auto typePet = schema::InterfaceType::Make(R"gql(Pet)gql"sv, R"md()md"sv); - schema->AddType(R"gql(Pet)gql"sv, typePet); - auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md(GraphQL validation [sample](http://spec.graphql.org/June2018/#example-26a9d))md"); - schema->AddType(R"gql(Query)gql"sv, typeQuery); - auto typeDog = schema::ObjectType::Make(R"gql(Dog)gql"sv, R"md()md"); - schema->AddType(R"gql(Dog)gql"sv, typeDog); - auto typeAlien = schema::ObjectType::Make(R"gql(Alien)gql"sv, R"md()md"); - schema->AddType(R"gql(Alien)gql"sv, typeAlien); - auto typeHuman = schema::ObjectType::Make(R"gql(Human)gql"sv, R"md()md"); - schema->AddType(R"gql(Human)gql"sv, typeHuman); - auto typeCat = schema::ObjectType::Make(R"gql(Cat)gql"sv, R"md()md"); - schema->AddType(R"gql(Cat)gql"sv, typeCat); - auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md(Support for [Counter Example 94](http://spec.graphql.org/June2018/#example-77c2e))md"); - schema->AddType(R"gql(Mutation)gql"sv, typeMutation); - auto typeMutateDogResult = schema::ObjectType::Make(R"gql(MutateDogResult)gql"sv, R"md(Support for [Counter Example 94](http://spec.graphql.org/June2018/#example-77c2e))md"); - schema->AddType(R"gql(MutateDogResult)gql"sv, typeMutateDogResult); - auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md(Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b))md"); - schema->AddType(R"gql(Subscription)gql"sv, typeSubscription); - auto typeMessage = schema::ObjectType::Make(R"gql(Message)gql"sv, R"md(Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b))md"); - schema->AddType(R"gql(Message)gql"sv, typeMessage); - auto typeArguments = schema::ObjectType::Make(R"gql(Arguments)gql"sv, R"md(Support for [Example 120](http://spec.graphql.org/June2018/#example-1891c))md"); - schema->AddType(R"gql(Arguments)gql"sv, typeArguments); - - typeDogCommand->AddEnumValues({ - { service::s_namesDogCommand[static_cast(validation::DogCommand::SIT)], R"md()md"sv, std::nullopt }, - { service::s_namesDogCommand[static_cast(validation::DogCommand::DOWN)], R"md()md"sv, std::nullopt }, - { service::s_namesDogCommand[static_cast(validation::DogCommand::HEEL)], R"md()md"sv, std::nullopt } - }); - typeCatCommand->AddEnumValues({ - { service::s_namesCatCommand[static_cast(validation::CatCommand::JUMP)], R"md()md"sv, std::nullopt } - }); - - typeComplexInput->AddInputValues({ - schema::InputValue::Make(R"gql(name)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv), - schema::InputValue::Make(R"gql(owner)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) - }); - - typeCatOrDog->AddPossibleTypes({ - schema->LookupType(R"gql(Cat)gql"sv), - schema->LookupType(R"gql(Dog)gql"sv) - }); - typeDogOrHuman->AddPossibleTypes({ - schema->LookupType(R"gql(Dog)gql"sv), - schema->LookupType(R"gql(Human)gql"sv) - }); - typeHumanOrAlien->AddPossibleTypes({ - schema->LookupType(R"gql(Human)gql"sv), - schema->LookupType(R"gql(Alien)gql"sv) - }); - - typeSentient->AddFields({ - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))) - }); - typePet->AddFields({ - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))) - }); - - typeQuery->AddFields({ - schema::Field::Make(R"gql(dog)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Dog")), - schema::Field::Make(R"gql(human)gql"sv, R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md"sv, std::nullopt, schema->LookupType("Human")), - schema::Field::Make(R"gql(pet)gql"sv, R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md"sv, std::nullopt, schema->LookupType("Pet")), - schema::Field::Make(R"gql(catOrDog)gql"sv, R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md"sv, std::nullopt, schema->LookupType("CatOrDog")), - schema::Field::Make(R"gql(arguments)gql"sv, R"md(Support for [Example 120](http://spec.graphql.org/June2018/#example-1891c))md"sv, std::nullopt, schema->LookupType("Arguments")), - schema::Field::Make(R"gql(findDog)gql"sv, R"md([Example 155](http://spec.graphql.org/June2018/#example-f3185))md"sv, std::nullopt, schema->LookupType("Dog"), { - schema::InputValue::Make(R"gql(complex)gql"sv, R"md()md"sv, schema->LookupType("ComplexInput"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(booleanList)gql"sv, R"md([Example 155](http://spec.graphql.org/June2018/#example-f3185))md"sv, std::nullopt, schema->LookupType("Boolean"), { - schema::InputValue::Make(R"gql(booleanListArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), R"gql()gql"sv) - }) - }); - typeDog->AddInterfaces({ - typePet - }); - typeDog->AddFields({ - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(nickname)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(barkVolume)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Int")), - schema::Field::Make(R"gql(doesKnowCommand)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), { - schema::InputValue::Make(R"gql(dogCommand)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("DogCommand")), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(isHousetrained)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), { - schema::InputValue::Make(R"gql(atOtherHomes)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(owner)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Human")) - }); - typeAlien->AddInterfaces({ - typeSentient - }); - typeAlien->AddFields({ - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(homePlanet)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); - typeHuman->AddInterfaces({ - typeSentient - }); - typeHuman->AddFields({ - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(pets)gql"sv, R"md(Support for [Counter Example 136](http://spec.graphql.org/June2018/#example-6bbad))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Pet"))))) - }); - typeCat->AddInterfaces({ - typePet - }); - typeCat->AddFields({ - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(nickname)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(doesKnowCommand)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), { - schema::InputValue::Make(R"gql(catCommand)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CatCommand")), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(meowVolume)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Int")) - }); - typeMutation->AddFields({ - schema::Field::Make(R"gql(mutateDog)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("MutateDogResult")) - }); - typeMutateDogResult->AddFields({ - schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) - }); - typeSubscription->AddFields({ - schema::Field::Make(R"gql(newMessage)gql"sv, R"md(Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Message"))), - schema::Field::Make(R"gql(disallowedSecondRootField)gql"sv, R"md(Support for [Counter Example 99](http://spec.graphql.org/June2018/#example-3997d) - [Counter Example 100](http://spec.graphql.org/June2018/#example-18466))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) - }); - typeMessage->AddFields({ - schema::Field::Make(R"gql(body)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(sender)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) - }); - typeArguments->AddFields({ - schema::Field::Make(R"gql(multipleReqs)gql"sv, R"md(Support for [Example 121](http://spec.graphql.org/June2018/#example-18fab))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int")), { - schema::InputValue::Make(R"gql(x)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int")), R"gql()gql"sv), - schema::InputValue::Make(R"gql(y)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int")), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(booleanArgField)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Boolean"), { - schema::InputValue::Make(R"gql(booleanArg)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(floatArgField)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Float"), { - schema::InputValue::Make(R"gql(floatArg)gql"sv, R"md()md"sv, schema->LookupType("Float"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(intArgField)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Int"), { - schema::InputValue::Make(R"gql(intArg)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(nonNullBooleanArgField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), { - schema::InputValue::Make(R"gql(nonNullBooleanArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(nonNullBooleanListField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), { - schema::InputValue::Make(R"gql(nonNullBooleanListArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(booleanListArgField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Boolean")), { - schema::InputValue::Make(R"gql(booleanListArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Boolean"))), R"gql()gql"sv) - }), - schema::Field::Make(R"gql(optionalNonNullBooleanArgField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), { - schema::InputValue::Make(R"gql(optionalBooleanArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql(false)gql"sv) - }) - }); - - schema->AddQueryType(typeQuery); - schema->AddMutationType(typeMutation); - schema->AddSubscriptionType(typeSubscription); -} - -std::shared_ptr GetSchema() -{ - static std::weak_ptr s_wpSchema; - auto schema = s_wpSchema.lock(); - - if (!schema) - { - schema = std::make_shared(false); - introspection::AddTypesToSchema(schema); - AddTypesToSchema(schema); - s_wpSchema = schema; - } - - return schema; -} - -} // namespace validation -} // namespace graphql diff --git a/samples/validation/ValidationSchema.h b/samples/validation/ValidationSchema.h deleted file mode 100644 index 66b73292..00000000 --- a/samples/validation/ValidationSchema.h +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#pragma once - -#ifndef VALIDATIONSCHEMA_H -#define VALIDATIONSCHEMA_H - -#include "graphqlservice/internal/Schema.h" - -// Check if the library version is compatible with schemagen 3.6.0 -static_assert(graphql::internal::MajorVersion == 3, "regenerate with schemagen: major version mismatch"); -static_assert(graphql::internal::MinorVersion == 6, "regenerate with schemagen: minor version mismatch"); - -#include -#include -#include - -namespace graphql { -namespace validation { - -enum class DogCommand -{ - SIT, - DOWN, - HEEL -}; - -enum class CatCommand -{ - JUMP -}; - -struct ComplexInput -{ - std::optional name; - std::optional owner; -}; - -namespace object { - -class Query; -class Dog; -class Alien; -class Human; -class Cat; -class Mutation; -class MutateDogResult; -class Subscription; -class Message; -class Arguments; - -} // namespace object - -struct Sentient; -struct Pet; - -struct Sentient -{ - virtual service::FieldResult getName(service::FieldParams&& params) const = 0; -}; - -struct Pet -{ - virtual service::FieldResult getName(service::FieldParams&& params) const = 0; -}; - -namespace object { - -class Query - : public service::Object -{ -protected: - explicit Query(); - -public: - virtual service::FieldResult> getDog(service::FieldParams&& params) const; - virtual service::FieldResult> getHuman(service::FieldParams&& params) const; - virtual service::FieldResult> getPet(service::FieldParams&& params) const; - virtual service::FieldResult> getCatOrDog(service::FieldParams&& params) const; - virtual service::FieldResult> getArguments(service::FieldParams&& params) const; - virtual service::FieldResult> getFindDog(service::FieldParams&& params, std::optional&& complexArg) const; - virtual service::FieldResult> getBooleanList(service::FieldParams&& params, std::optional>&& booleanListArgArg) const; - -private: - std::future resolveDog(service::ResolverParams&& params); - std::future resolveHuman(service::ResolverParams&& params); - std::future resolvePet(service::ResolverParams&& params); - std::future resolveCatOrDog(service::ResolverParams&& params); - std::future resolveArguments(service::ResolverParams&& params); - std::future resolveFindDog(service::ResolverParams&& params); - std::future resolveBooleanList(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); - std::future resolve_schema(service::ResolverParams&& params); - std::future resolve_type(service::ResolverParams&& params); - - std::shared_ptr _schema; -}; - -class Dog - : public service::Object - , public Pet -{ -protected: - explicit Dog(); - -public: - virtual service::FieldResult getName(service::FieldParams&& params) const override; - virtual service::FieldResult> getNickname(service::FieldParams&& params) const; - virtual service::FieldResult> getBarkVolume(service::FieldParams&& params) const; - virtual service::FieldResult getDoesKnowCommand(service::FieldParams&& params, DogCommand&& dogCommandArg) const; - virtual service::FieldResult getIsHousetrained(service::FieldParams&& params, std::optional&& atOtherHomesArg) const; - virtual service::FieldResult> getOwner(service::FieldParams&& params) const; - -private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveNickname(service::ResolverParams&& params); - std::future resolveBarkVolume(service::ResolverParams&& params); - std::future resolveDoesKnowCommand(service::ResolverParams&& params); - std::future resolveIsHousetrained(service::ResolverParams&& params); - std::future resolveOwner(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Alien - : public service::Object - , public Sentient -{ -protected: - explicit Alien(); - -public: - virtual service::FieldResult getName(service::FieldParams&& params) const override; - virtual service::FieldResult> getHomePlanet(service::FieldParams&& params) const; - -private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveHomePlanet(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Human - : public service::Object - , public Sentient -{ -protected: - explicit Human(); - -public: - virtual service::FieldResult getName(service::FieldParams&& params) const override; - virtual service::FieldResult>> getPets(service::FieldParams&& params) const; - -private: - std::future resolveName(service::ResolverParams&& params); - std::future resolvePets(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Cat - : public service::Object - , public Pet -{ -protected: - explicit Cat(); - -public: - virtual service::FieldResult getName(service::FieldParams&& params) const override; - virtual service::FieldResult> getNickname(service::FieldParams&& params) const; - virtual service::FieldResult getDoesKnowCommand(service::FieldParams&& params, CatCommand&& catCommandArg) const; - virtual service::FieldResult> getMeowVolume(service::FieldParams&& params) const; - -private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveNickname(service::ResolverParams&& params); - std::future resolveDoesKnowCommand(service::ResolverParams&& params); - std::future resolveMeowVolume(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Mutation - : public service::Object -{ -protected: - explicit Mutation(); - -public: - virtual service::FieldResult> applyMutateDog(service::FieldParams&& params) const; - -private: - std::future resolveMutateDog(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class MutateDogResult - : public service::Object -{ -protected: - explicit MutateDogResult(); - -public: - virtual service::FieldResult getId(service::FieldParams&& params) const; - -private: - std::future resolveId(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Subscription - : public service::Object -{ -protected: - explicit Subscription(); - -public: - virtual service::FieldResult> getNewMessage(service::FieldParams&& params) const; - virtual service::FieldResult getDisallowedSecondRootField(service::FieldParams&& params) const; - -private: - std::future resolveNewMessage(service::ResolverParams&& params); - std::future resolveDisallowedSecondRootField(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Message - : public service::Object -{ -protected: - explicit Message(); - -public: - virtual service::FieldResult> getBody(service::FieldParams&& params) const; - virtual service::FieldResult getSender(service::FieldParams&& params) const; - -private: - std::future resolveBody(service::ResolverParams&& params); - std::future resolveSender(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -class Arguments - : public service::Object -{ -protected: - explicit Arguments(); - -public: - virtual service::FieldResult getMultipleReqs(service::FieldParams&& params, response::IntType&& xArg, response::IntType&& yArg) const; - virtual service::FieldResult> getBooleanArgField(service::FieldParams&& params, std::optional&& booleanArgArg) const; - virtual service::FieldResult> getFloatArgField(service::FieldParams&& params, std::optional&& floatArgArg) const; - virtual service::FieldResult> getIntArgField(service::FieldParams&& params, std::optional&& intArgArg) const; - virtual service::FieldResult getNonNullBooleanArgField(service::FieldParams&& params, response::BooleanType&& nonNullBooleanArgArg) const; - virtual service::FieldResult>> getNonNullBooleanListField(service::FieldParams&& params, std::optional>&& nonNullBooleanListArgArg) const; - virtual service::FieldResult>>> getBooleanListArgField(service::FieldParams&& params, std::vector>&& booleanListArgArg) const; - virtual service::FieldResult getOptionalNonNullBooleanArgField(service::FieldParams&& params, response::BooleanType&& optionalBooleanArgArg) const; - -private: - std::future resolveMultipleReqs(service::ResolverParams&& params); - std::future resolveBooleanArgField(service::ResolverParams&& params); - std::future resolveFloatArgField(service::ResolverParams&& params); - std::future resolveIntArgField(service::ResolverParams&& params); - std::future resolveNonNullBooleanArgField(service::ResolverParams&& params); - std::future resolveNonNullBooleanListField(service::ResolverParams&& params); - std::future resolveBooleanListArgField(service::ResolverParams&& params); - std::future resolveOptionalNonNullBooleanArgField(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); -}; - -} // namespace object - -class Operations - : public service::Request -{ -public: - explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription); - -private: - std::shared_ptr _query; - std::shared_ptr _mutation; - std::shared_ptr _subscription; -}; - -std::shared_ptr GetSchema(); - -} // namespace validation -} // namespace graphql - -#endif // VALIDATIONSCHEMA_H diff --git a/samples/validation/schema/AlienObject.cpp b/samples/validation/schema/AlienObject.cpp new file mode 100644 index 00000000..8e16931e --- /dev/null +++ b/samples/validation/schema/AlienObject.cpp @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "AlienObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Alien::Alien(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Alien::getTypeNames() const noexcept +{ + return { + R"gql(Sentient)gql"sv, + R"gql(HumanOrAlien)gql"sv, + R"gql(Alien)gql"sv + }; +} + +service::ResolverMap Alien::getResolvers() const noexcept +{ + return { + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(homePlanet)gql"sv, [this](service::ResolverParams&& params) { return resolveHomePlanet(std::move(params)); } } + }; +} + +void Alien::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Alien::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Alien::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Alien::resolveHomePlanet(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getHomePlanet(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Alien::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Alien)gql" }, std::move(params)); +} + +} // namespace object + +void AddAlienDetails(const std::shared_ptr& typeAlien, const std::shared_ptr& schema) +{ + typeAlien->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Sentient)gql"sv)) + }); + typeAlien->AddFields({ + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(homePlanet)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/AlienObject.h b/samples/validation/schema/AlienObject.h new file mode 100644 index 00000000..18456bca --- /dev/null +++ b/samples/validation/schema/AlienObject.h @@ -0,0 +1,174 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef ALIENOBJECT_H +#define ALIENOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { +namespace implements { + +template +concept AlienIs = std::is_same_v || std::is_same_v; + +} // namespace implements + +namespace methods::AlienHas { + +template +concept getNameWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getName(std::move(params)) } }; +}; + +template +concept getName = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getName() } }; +}; + +template +concept getHomePlanetWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getHomePlanet(std::move(params)) } }; +}; + +template +concept getHomePlanet = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getHomePlanet() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::AlienHas + +class Alien + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveHomePlanet(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getName(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getHomePlanet(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName(service::FieldParams&& params) const final + { + if constexpr (methods::AlienHas::getNameWithParams) + { + return { _pimpl->getName(std::move(params)) }; + } + else if constexpr (methods::AlienHas::getName) + { + return { _pimpl->getName() }; + } + else + { + throw std::runtime_error(R"ex(Alien::getName is not implemented)ex"); + } + } + + service::AwaitableScalar> getHomePlanet(service::FieldParams&& params) const final + { + if constexpr (methods::AlienHas::getHomePlanetWithParams) + { + return { _pimpl->getHomePlanet(std::move(params)) }; + } + else if constexpr (methods::AlienHas::getHomePlanet) + { + return { _pimpl->getHomePlanet() }; + } + else + { + throw std::runtime_error(R"ex(Alien::getHomePlanet is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AlienHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::AlienHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Alien(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Sentient; + + // Unions which include this type + friend HumanOrAlien; + + template + static constexpr bool implements() noexcept + { + return implements::AlienIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Alien(std::shared_ptr pimpl) noexcept + : Alien { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::validation::object + +#endif // ALIENOBJECT_H diff --git a/samples/validation/schema/ArgumentsObject.cpp b/samples/validation/schema/ArgumentsObject.cpp new file mode 100644 index 00000000..a95e0cea --- /dev/null +++ b/samples/validation/schema/ArgumentsObject.cpp @@ -0,0 +1,202 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "ArgumentsObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Arguments::Arguments(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Arguments::getTypeNames() const noexcept +{ + return { + R"gql(Arguments)gql"sv + }; +} + +service::ResolverMap Arguments::getResolvers() const noexcept +{ + return { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(intArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveIntArgField(std::move(params)); } }, + { R"gql(multipleReqs)gql"sv, [this](service::ResolverParams&& params) { return resolveMultipleReqs(std::move(params)); } }, + { R"gql(floatArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveFloatArgField(std::move(params)); } }, + { R"gql(booleanArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveBooleanArgField(std::move(params)); } }, + { R"gql(booleanListArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveBooleanListArgField(std::move(params)); } }, + { R"gql(nonNullBooleanArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveNonNullBooleanArgField(std::move(params)); } }, + { R"gql(nonNullBooleanListField)gql"sv, [this](service::ResolverParams&& params) { return resolveNonNullBooleanListField(std::move(params)); } }, + { R"gql(optionalNonNullBooleanArgField)gql"sv, [this](service::ResolverParams&& params) { return resolveOptionalNonNullBooleanArgField(std::move(params)); } } + }; +} + +void Arguments::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Arguments::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Arguments::resolveMultipleReqs(service::ResolverParams&& params) const +{ + auto argX = service::ModifiedArgument::require("x", params.arguments); + auto argY = service::ModifiedArgument::require("y", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getMultipleReqs(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argX), std::move(argY)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Arguments::resolveBooleanArgField(service::ResolverParams&& params) const +{ + auto argBooleanArg = service::ModifiedArgument::require("booleanArg", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getBooleanArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argBooleanArg)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Arguments::resolveFloatArgField(service::ResolverParams&& params) const +{ + auto argFloatArg = service::ModifiedArgument::require("floatArg", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getFloatArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argFloatArg)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Arguments::resolveIntArgField(service::ResolverParams&& params) const +{ + auto argIntArg = service::ModifiedArgument::require("intArg", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getIntArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIntArg)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Arguments::resolveNonNullBooleanArgField(service::ResolverParams&& params) const +{ + auto argNonNullBooleanArg = service::ModifiedArgument::require("nonNullBooleanArg", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNonNullBooleanArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argNonNullBooleanArg)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Arguments::resolveNonNullBooleanListField(service::ResolverParams&& params) const +{ + auto argNonNullBooleanListArg = service::ModifiedArgument::require("nonNullBooleanListArg", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNonNullBooleanListField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argNonNullBooleanListArg)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Arguments::resolveBooleanListArgField(service::ResolverParams&& params) const +{ + auto argBooleanListArg = service::ModifiedArgument::require("booleanListArg", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getBooleanListArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argBooleanListArg)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Arguments::resolveOptionalNonNullBooleanArgField(service::ResolverParams&& params) const +{ + static const auto defaultArguments = []() + { + response::Value values(response::Type::Map); + response::Value entry; + + entry = response::Value(false); + values.emplace_back("optionalBooleanArg", std::move(entry)); + + return values; + }(); + + auto pairOptionalBooleanArg = service::ModifiedArgument::find("optionalBooleanArg", params.arguments); + auto argOptionalBooleanArg = (pairOptionalBooleanArg.second + ? std::move(pairOptionalBooleanArg.first) + : service::ModifiedArgument::require("optionalBooleanArg", defaultArguments)); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getOptionalNonNullBooleanArgField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argOptionalBooleanArg)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Arguments::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Arguments)gql" }, std::move(params)); +} + +} // namespace object + +void AddArgumentsDetails(const std::shared_ptr& typeArguments, const std::shared_ptr& schema) +{ + typeArguments->AddFields({ + schema::Field::Make(R"gql(multipleReqs)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv)), { + schema::InputValue::Make(R"gql(x)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv)), R"gql()gql"sv), + schema::InputValue::Make(R"gql(y)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv)), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(booleanArgField)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Boolean)gql"sv), { + schema::InputValue::Make(R"gql(booleanArg)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Boolean)gql"sv), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(floatArgField)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Float)gql"sv), { + schema::InputValue::Make(R"gql(floatArg)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Float)gql"sv), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(intArgField)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Int)gql"sv), { + schema::InputValue::Make(R"gql(intArg)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(nonNullBooleanArgField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv)), { + schema::InputValue::Make(R"gql(nonNullBooleanArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv)), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(nonNullBooleanListField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))), { + schema::InputValue::Make(R"gql(nonNullBooleanListArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(booleanListArgField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Boolean)gql"sv)), { + schema::InputValue::Make(R"gql(booleanListArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType(R"gql(Boolean)gql"sv))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(optionalNonNullBooleanArgField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv)), { + schema::InputValue::Make(R"gql(optionalBooleanArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv)), R"gql(false)gql"sv) + }) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/ArgumentsObject.h b/samples/validation/schema/ArgumentsObject.h new file mode 100644 index 00000000..d9f72e75 --- /dev/null +++ b/samples/validation/schema/ArgumentsObject.h @@ -0,0 +1,335 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef ARGUMENTSOBJECT_H +#define ARGUMENTSOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { +namespace methods::ArgumentsHas { + +template +concept getMultipleReqsWithParams = requires (TImpl impl, service::FieldParams params, int xArg, int yArg) +{ + { service::AwaitableScalar { impl.getMultipleReqs(std::move(params), std::move(xArg), std::move(yArg)) } }; +}; + +template +concept getMultipleReqs = requires (TImpl impl, int xArg, int yArg) +{ + { service::AwaitableScalar { impl.getMultipleReqs(std::move(xArg), std::move(yArg)) } }; +}; + +template +concept getBooleanArgFieldWithParams = requires (TImpl impl, service::FieldParams params, std::optional booleanArgArg) +{ + { service::AwaitableScalar> { impl.getBooleanArgField(std::move(params), std::move(booleanArgArg)) } }; +}; + +template +concept getBooleanArgField = requires (TImpl impl, std::optional booleanArgArg) +{ + { service::AwaitableScalar> { impl.getBooleanArgField(std::move(booleanArgArg)) } }; +}; + +template +concept getFloatArgFieldWithParams = requires (TImpl impl, service::FieldParams params, std::optional floatArgArg) +{ + { service::AwaitableScalar> { impl.getFloatArgField(std::move(params), std::move(floatArgArg)) } }; +}; + +template +concept getFloatArgField = requires (TImpl impl, std::optional floatArgArg) +{ + { service::AwaitableScalar> { impl.getFloatArgField(std::move(floatArgArg)) } }; +}; + +template +concept getIntArgFieldWithParams = requires (TImpl impl, service::FieldParams params, std::optional intArgArg) +{ + { service::AwaitableScalar> { impl.getIntArgField(std::move(params), std::move(intArgArg)) } }; +}; + +template +concept getIntArgField = requires (TImpl impl, std::optional intArgArg) +{ + { service::AwaitableScalar> { impl.getIntArgField(std::move(intArgArg)) } }; +}; + +template +concept getNonNullBooleanArgFieldWithParams = requires (TImpl impl, service::FieldParams params, bool nonNullBooleanArgArg) +{ + { service::AwaitableScalar { impl.getNonNullBooleanArgField(std::move(params), std::move(nonNullBooleanArgArg)) } }; +}; + +template +concept getNonNullBooleanArgField = requires (TImpl impl, bool nonNullBooleanArgArg) +{ + { service::AwaitableScalar { impl.getNonNullBooleanArgField(std::move(nonNullBooleanArgArg)) } }; +}; + +template +concept getNonNullBooleanListFieldWithParams = requires (TImpl impl, service::FieldParams params, std::optional> nonNullBooleanListArgArg) +{ + { service::AwaitableScalar>> { impl.getNonNullBooleanListField(std::move(params), std::move(nonNullBooleanListArgArg)) } }; +}; + +template +concept getNonNullBooleanListField = requires (TImpl impl, std::optional> nonNullBooleanListArgArg) +{ + { service::AwaitableScalar>> { impl.getNonNullBooleanListField(std::move(nonNullBooleanListArgArg)) } }; +}; + +template +concept getBooleanListArgFieldWithParams = requires (TImpl impl, service::FieldParams params, std::vector> booleanListArgArg) +{ + { service::AwaitableScalar>>> { impl.getBooleanListArgField(std::move(params), std::move(booleanListArgArg)) } }; +}; + +template +concept getBooleanListArgField = requires (TImpl impl, std::vector> booleanListArgArg) +{ + { service::AwaitableScalar>>> { impl.getBooleanListArgField(std::move(booleanListArgArg)) } }; +}; + +template +concept getOptionalNonNullBooleanArgFieldWithParams = requires (TImpl impl, service::FieldParams params, bool optionalBooleanArgArg) +{ + { service::AwaitableScalar { impl.getOptionalNonNullBooleanArgField(std::move(params), std::move(optionalBooleanArgArg)) } }; +}; + +template +concept getOptionalNonNullBooleanArgField = requires (TImpl impl, bool optionalBooleanArgArg) +{ + { service::AwaitableScalar { impl.getOptionalNonNullBooleanArgField(std::move(optionalBooleanArgArg)) } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::ArgumentsHas + +class Arguments + : public service::Object +{ +private: + service::AwaitableResolver resolveMultipleReqs(service::ResolverParams&& params) const; + service::AwaitableResolver resolveBooleanArgField(service::ResolverParams&& params) const; + service::AwaitableResolver resolveFloatArgField(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIntArgField(service::ResolverParams&& params) const; + service::AwaitableResolver resolveNonNullBooleanArgField(service::ResolverParams&& params) const; + service::AwaitableResolver resolveNonNullBooleanListField(service::ResolverParams&& params) const; + service::AwaitableResolver resolveBooleanListArgField(service::ResolverParams&& params) const; + service::AwaitableResolver resolveOptionalNonNullBooleanArgField(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getMultipleReqs(service::FieldParams&& params, int&& xArg, int&& yArg) const = 0; + virtual service::AwaitableScalar> getBooleanArgField(service::FieldParams&& params, std::optional&& booleanArgArg) const = 0; + virtual service::AwaitableScalar> getFloatArgField(service::FieldParams&& params, std::optional&& floatArgArg) const = 0; + virtual service::AwaitableScalar> getIntArgField(service::FieldParams&& params, std::optional&& intArgArg) const = 0; + virtual service::AwaitableScalar getNonNullBooleanArgField(service::FieldParams&& params, bool&& nonNullBooleanArgArg) const = 0; + virtual service::AwaitableScalar>> getNonNullBooleanListField(service::FieldParams&& params, std::optional>&& nonNullBooleanListArgArg) const = 0; + virtual service::AwaitableScalar>>> getBooleanListArgField(service::FieldParams&& params, std::vector>&& booleanListArgArg) const = 0; + virtual service::AwaitableScalar getOptionalNonNullBooleanArgField(service::FieldParams&& params, bool&& optionalBooleanArgArg) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getMultipleReqs(service::FieldParams&& params, int&& xArg, int&& yArg) const final + { + if constexpr (methods::ArgumentsHas::getMultipleReqsWithParams) + { + return { _pimpl->getMultipleReqs(std::move(params), std::move(xArg), std::move(yArg)) }; + } + else if constexpr (methods::ArgumentsHas::getMultipleReqs) + { + return { _pimpl->getMultipleReqs(std::move(xArg), std::move(yArg)) }; + } + else + { + throw std::runtime_error(R"ex(Arguments::getMultipleReqs is not implemented)ex"); + } + } + + service::AwaitableScalar> getBooleanArgField(service::FieldParams&& params, std::optional&& booleanArgArg) const final + { + if constexpr (methods::ArgumentsHas::getBooleanArgFieldWithParams) + { + return { _pimpl->getBooleanArgField(std::move(params), std::move(booleanArgArg)) }; + } + else if constexpr (methods::ArgumentsHas::getBooleanArgField) + { + return { _pimpl->getBooleanArgField(std::move(booleanArgArg)) }; + } + else + { + throw std::runtime_error(R"ex(Arguments::getBooleanArgField is not implemented)ex"); + } + } + + service::AwaitableScalar> getFloatArgField(service::FieldParams&& params, std::optional&& floatArgArg) const final + { + if constexpr (methods::ArgumentsHas::getFloatArgFieldWithParams) + { + return { _pimpl->getFloatArgField(std::move(params), std::move(floatArgArg)) }; + } + else if constexpr (methods::ArgumentsHas::getFloatArgField) + { + return { _pimpl->getFloatArgField(std::move(floatArgArg)) }; + } + else + { + throw std::runtime_error(R"ex(Arguments::getFloatArgField is not implemented)ex"); + } + } + + service::AwaitableScalar> getIntArgField(service::FieldParams&& params, std::optional&& intArgArg) const final + { + if constexpr (methods::ArgumentsHas::getIntArgFieldWithParams) + { + return { _pimpl->getIntArgField(std::move(params), std::move(intArgArg)) }; + } + else if constexpr (methods::ArgumentsHas::getIntArgField) + { + return { _pimpl->getIntArgField(std::move(intArgArg)) }; + } + else + { + throw std::runtime_error(R"ex(Arguments::getIntArgField is not implemented)ex"); + } + } + + service::AwaitableScalar getNonNullBooleanArgField(service::FieldParams&& params, bool&& nonNullBooleanArgArg) const final + { + if constexpr (methods::ArgumentsHas::getNonNullBooleanArgFieldWithParams) + { + return { _pimpl->getNonNullBooleanArgField(std::move(params), std::move(nonNullBooleanArgArg)) }; + } + else if constexpr (methods::ArgumentsHas::getNonNullBooleanArgField) + { + return { _pimpl->getNonNullBooleanArgField(std::move(nonNullBooleanArgArg)) }; + } + else + { + throw std::runtime_error(R"ex(Arguments::getNonNullBooleanArgField is not implemented)ex"); + } + } + + service::AwaitableScalar>> getNonNullBooleanListField(service::FieldParams&& params, std::optional>&& nonNullBooleanListArgArg) const final + { + if constexpr (methods::ArgumentsHas::getNonNullBooleanListFieldWithParams) + { + return { _pimpl->getNonNullBooleanListField(std::move(params), std::move(nonNullBooleanListArgArg)) }; + } + else if constexpr (methods::ArgumentsHas::getNonNullBooleanListField) + { + return { _pimpl->getNonNullBooleanListField(std::move(nonNullBooleanListArgArg)) }; + } + else + { + throw std::runtime_error(R"ex(Arguments::getNonNullBooleanListField is not implemented)ex"); + } + } + + service::AwaitableScalar>>> getBooleanListArgField(service::FieldParams&& params, std::vector>&& booleanListArgArg) const final + { + if constexpr (methods::ArgumentsHas::getBooleanListArgFieldWithParams) + { + return { _pimpl->getBooleanListArgField(std::move(params), std::move(booleanListArgArg)) }; + } + else if constexpr (methods::ArgumentsHas::getBooleanListArgField) + { + return { _pimpl->getBooleanListArgField(std::move(booleanListArgArg)) }; + } + else + { + throw std::runtime_error(R"ex(Arguments::getBooleanListArgField is not implemented)ex"); + } + } + + service::AwaitableScalar getOptionalNonNullBooleanArgField(service::FieldParams&& params, bool&& optionalBooleanArgArg) const final + { + if constexpr (methods::ArgumentsHas::getOptionalNonNullBooleanArgFieldWithParams) + { + return { _pimpl->getOptionalNonNullBooleanArgField(std::move(params), std::move(optionalBooleanArgArg)) }; + } + else if constexpr (methods::ArgumentsHas::getOptionalNonNullBooleanArgField) + { + return { _pimpl->getOptionalNonNullBooleanArgField(std::move(optionalBooleanArgArg)) }; + } + else + { + throw std::runtime_error(R"ex(Arguments::getOptionalNonNullBooleanArgField is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::ArgumentsHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::ArgumentsHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Arguments(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Arguments(std::shared_ptr pimpl) noexcept + : Arguments { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::validation::object + +#endif // ARGUMENTSOBJECT_H diff --git a/samples/validation/schema/CMakeLists.txt b/samples/validation/schema/CMakeLists.txt new file mode 100644 index 00000000..739d675e --- /dev/null +++ b/samples/validation/schema/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +# Normally this would be handled by find_package(cppgraphqlgen CONFIG). +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/cppgraphqlgen-functions.cmake) + +if(GRAPHQL_UPDATE_SAMPLES) + update_graphql_schema_files(validation schema.validation.graphql Validation validation --stubs --no-introspection) +endif() + +add_graphql_schema_no_introspection_target(validation) diff --git a/samples/validation/schema/CatObject.cpp b/samples/validation/schema/CatObject.cpp new file mode 100644 index 00000000..893261fa --- /dev/null +++ b/samples/validation/schema/CatObject.cpp @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "CatObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Cat::Cat(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Cat::getTypeNames() const noexcept +{ + return { + R"gql(Pet)gql"sv, + R"gql(CatOrDog)gql"sv, + R"gql(Cat)gql"sv + }; +} + +service::ResolverMap Cat::getResolvers() const noexcept +{ + return { + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(nickname)gql"sv, [this](service::ResolverParams&& params) { return resolveNickname(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(meowVolume)gql"sv, [this](service::ResolverParams&& params) { return resolveMeowVolume(std::move(params)); } }, + { R"gql(doesKnowCommand)gql"sv, [this](service::ResolverParams&& params) { return resolveDoesKnowCommand(std::move(params)); } } + }; +} + +void Cat::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Cat::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Cat::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Cat::resolveNickname(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNickname(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Cat::resolveDoesKnowCommand(service::ResolverParams&& params) const +{ + auto argCatCommand = service::ModifiedArgument::require("catCommand", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getDoesKnowCommand(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argCatCommand)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Cat::resolveMeowVolume(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getMeowVolume(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Cat::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Cat)gql" }, std::move(params)); +} + +} // namespace object + +void AddCatDetails(const std::shared_ptr& typeCat, const std::shared_ptr& schema) +{ + typeCat->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Pet)gql"sv)) + }); + typeCat->AddFields({ + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(nickname)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(doesKnowCommand)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv)), { + schema::InputValue::Make(R"gql(catCommand)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(CatCommand)gql"sv)), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(meowVolume)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Int)gql"sv)) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/CatObject.h b/samples/validation/schema/CatObject.h new file mode 100644 index 00000000..47829209 --- /dev/null +++ b/samples/validation/schema/CatObject.h @@ -0,0 +1,234 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef CATOBJECT_H +#define CATOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { +namespace implements { + +template +concept CatIs = std::is_same_v || std::is_same_v; + +} // namespace implements + +namespace methods::CatHas { + +template +concept getNameWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getName(std::move(params)) } }; +}; + +template +concept getName = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getName() } }; +}; + +template +concept getNicknameWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getNickname(std::move(params)) } }; +}; + +template +concept getNickname = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getNickname() } }; +}; + +template +concept getDoesKnowCommandWithParams = requires (TImpl impl, service::FieldParams params, CatCommand catCommandArg) +{ + { service::AwaitableScalar { impl.getDoesKnowCommand(std::move(params), std::move(catCommandArg)) } }; +}; + +template +concept getDoesKnowCommand = requires (TImpl impl, CatCommand catCommandArg) +{ + { service::AwaitableScalar { impl.getDoesKnowCommand(std::move(catCommandArg)) } }; +}; + +template +concept getMeowVolumeWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getMeowVolume(std::move(params)) } }; +}; + +template +concept getMeowVolume = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getMeowVolume() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::CatHas + +class Cat + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveNickname(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDoesKnowCommand(service::ResolverParams&& params) const; + service::AwaitableResolver resolveMeowVolume(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getName(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getNickname(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getDoesKnowCommand(service::FieldParams&& params, CatCommand&& catCommandArg) const = 0; + virtual service::AwaitableScalar> getMeowVolume(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName(service::FieldParams&& params) const final + { + if constexpr (methods::CatHas::getNameWithParams) + { + return { _pimpl->getName(std::move(params)) }; + } + else if constexpr (methods::CatHas::getName) + { + return { _pimpl->getName() }; + } + else + { + throw std::runtime_error(R"ex(Cat::getName is not implemented)ex"); + } + } + + service::AwaitableScalar> getNickname(service::FieldParams&& params) const final + { + if constexpr (methods::CatHas::getNicknameWithParams) + { + return { _pimpl->getNickname(std::move(params)) }; + } + else if constexpr (methods::CatHas::getNickname) + { + return { _pimpl->getNickname() }; + } + else + { + throw std::runtime_error(R"ex(Cat::getNickname is not implemented)ex"); + } + } + + service::AwaitableScalar getDoesKnowCommand(service::FieldParams&& params, CatCommand&& catCommandArg) const final + { + if constexpr (methods::CatHas::getDoesKnowCommandWithParams) + { + return { _pimpl->getDoesKnowCommand(std::move(params), std::move(catCommandArg)) }; + } + else if constexpr (methods::CatHas::getDoesKnowCommand) + { + return { _pimpl->getDoesKnowCommand(std::move(catCommandArg)) }; + } + else + { + throw std::runtime_error(R"ex(Cat::getDoesKnowCommand is not implemented)ex"); + } + } + + service::AwaitableScalar> getMeowVolume(service::FieldParams&& params) const final + { + if constexpr (methods::CatHas::getMeowVolumeWithParams) + { + return { _pimpl->getMeowVolume(std::move(params)) }; + } + else if constexpr (methods::CatHas::getMeowVolume) + { + return { _pimpl->getMeowVolume() }; + } + else + { + throw std::runtime_error(R"ex(Cat::getMeowVolume is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::CatHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::CatHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Cat(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Pet; + + // Unions which include this type + friend CatOrDog; + + template + static constexpr bool implements() noexcept + { + return implements::CatIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Cat(std::shared_ptr pimpl) noexcept + : Cat { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::validation::object + +#endif // CATOBJECT_H diff --git a/samples/validation/schema/CatOrDogObject.cpp b/samples/validation/schema/CatOrDogObject.cpp new file mode 100644 index 00000000..2b7a4d02 --- /dev/null +++ b/samples/validation/schema/CatOrDogObject.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "CatOrDogObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +CatOrDog::CatOrDog(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void CatOrDog::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void CatOrDog::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddCatOrDogDetails(const std::shared_ptr& typeCatOrDog, const std::shared_ptr& schema) +{ + typeCatOrDog->AddPossibleTypes({ + schema->LookupType(R"gql(Cat)gql"sv), + schema->LookupType(R"gql(Dog)gql"sv) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/CatOrDogObject.h b/samples/validation/schema/CatOrDogObject.h new file mode 100644 index 00000000..c6b43a7e --- /dev/null +++ b/samples/validation/schema/CatOrDogObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef CATORDOGOBJECT_H +#define CATORDOGOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { + +class CatOrDog + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + CatOrDog(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + CatOrDog(std::shared_ptr pimpl) noexcept + : CatOrDog { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "CatOrDog is not implemented"); + } +}; + +} // namespace graphql::validation::object + +#endif // CATORDOGOBJECT_H diff --git a/samples/validation/schema/DogObject.cpp b/samples/validation/schema/DogObject.cpp new file mode 100644 index 00000000..72c913e1 --- /dev/null +++ b/samples/validation/schema/DogObject.cpp @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "DogObject.h" +#include "HumanObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Dog::Dog(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Dog::getTypeNames() const noexcept +{ + return { + R"gql(Pet)gql"sv, + R"gql(CatOrDog)gql"sv, + R"gql(DogOrHuman)gql"sv, + R"gql(Dog)gql"sv + }; +} + +service::ResolverMap Dog::getResolvers() const noexcept +{ + return { + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(owner)gql"sv, [this](service::ResolverParams&& params) { return resolveOwner(std::move(params)); } }, + { R"gql(nickname)gql"sv, [this](service::ResolverParams&& params) { return resolveNickname(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(barkVolume)gql"sv, [this](service::ResolverParams&& params) { return resolveBarkVolume(std::move(params)); } }, + { R"gql(isHousetrained)gql"sv, [this](service::ResolverParams&& params) { return resolveIsHousetrained(std::move(params)); } }, + { R"gql(doesKnowCommand)gql"sv, [this](service::ResolverParams&& params) { return resolveDoesKnowCommand(std::move(params)); } } + }; +} + +void Dog::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Dog::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Dog::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Dog::resolveNickname(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNickname(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Dog::resolveBarkVolume(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getBarkVolume(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Dog::resolveDoesKnowCommand(service::ResolverParams&& params) const +{ + auto argDogCommand = service::ModifiedArgument::require("dogCommand", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getDoesKnowCommand(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argDogCommand)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Dog::resolveIsHousetrained(service::ResolverParams&& params) const +{ + auto argAtOtherHomes = service::ModifiedArgument::require("atOtherHomes", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getIsHousetrained(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argAtOtherHomes)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Dog::resolveOwner(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getOwner(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Dog::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Dog)gql" }, std::move(params)); +} + +} // namespace object + +void AddDogDetails(const std::shared_ptr& typeDog, const std::shared_ptr& schema) +{ + typeDog->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Pet)gql"sv)) + }); + typeDog->AddFields({ + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(nickname)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(barkVolume)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Int)gql"sv)), + schema::Field::Make(R"gql(doesKnowCommand)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv)), { + schema::InputValue::Make(R"gql(dogCommand)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(DogCommand)gql"sv)), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(isHousetrained)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv)), { + schema::InputValue::Make(R"gql(atOtherHomes)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Boolean)gql"sv), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(owner)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Human)gql"sv)) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/DogObject.h b/samples/validation/schema/DogObject.h new file mode 100644 index 00000000..bd8b3180 --- /dev/null +++ b/samples/validation/schema/DogObject.h @@ -0,0 +1,295 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef DOGOBJECT_H +#define DOGOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { +namespace implements { + +template +concept DogIs = std::is_same_v || std::is_same_v || std::is_same_v; + +} // namespace implements + +namespace methods::DogHas { + +template +concept getNameWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getName(std::move(params)) } }; +}; + +template +concept getName = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getName() } }; +}; + +template +concept getNicknameWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getNickname(std::move(params)) } }; +}; + +template +concept getNickname = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getNickname() } }; +}; + +template +concept getBarkVolumeWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getBarkVolume(std::move(params)) } }; +}; + +template +concept getBarkVolume = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getBarkVolume() } }; +}; + +template +concept getDoesKnowCommandWithParams = requires (TImpl impl, service::FieldParams params, DogCommand dogCommandArg) +{ + { service::AwaitableScalar { impl.getDoesKnowCommand(std::move(params), std::move(dogCommandArg)) } }; +}; + +template +concept getDoesKnowCommand = requires (TImpl impl, DogCommand dogCommandArg) +{ + { service::AwaitableScalar { impl.getDoesKnowCommand(std::move(dogCommandArg)) } }; +}; + +template +concept getIsHousetrainedWithParams = requires (TImpl impl, service::FieldParams params, std::optional atOtherHomesArg) +{ + { service::AwaitableScalar { impl.getIsHousetrained(std::move(params), std::move(atOtherHomesArg)) } }; +}; + +template +concept getIsHousetrained = requires (TImpl impl, std::optional atOtherHomesArg) +{ + { service::AwaitableScalar { impl.getIsHousetrained(std::move(atOtherHomesArg)) } }; +}; + +template +concept getOwnerWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getOwner(std::move(params)) } }; +}; + +template +concept getOwner = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getOwner() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::DogHas + +class Dog + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveNickname(service::ResolverParams&& params) const; + service::AwaitableResolver resolveBarkVolume(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDoesKnowCommand(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIsHousetrained(service::ResolverParams&& params) const; + service::AwaitableResolver resolveOwner(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getName(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getNickname(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar> getBarkVolume(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getDoesKnowCommand(service::FieldParams&& params, DogCommand&& dogCommandArg) const = 0; + virtual service::AwaitableScalar getIsHousetrained(service::FieldParams&& params, std::optional&& atOtherHomesArg) const = 0; + virtual service::AwaitableObject> getOwner(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName(service::FieldParams&& params) const final + { + if constexpr (methods::DogHas::getNameWithParams) + { + return { _pimpl->getName(std::move(params)) }; + } + else if constexpr (methods::DogHas::getName) + { + return { _pimpl->getName() }; + } + else + { + throw std::runtime_error(R"ex(Dog::getName is not implemented)ex"); + } + } + + service::AwaitableScalar> getNickname(service::FieldParams&& params) const final + { + if constexpr (methods::DogHas::getNicknameWithParams) + { + return { _pimpl->getNickname(std::move(params)) }; + } + else if constexpr (methods::DogHas::getNickname) + { + return { _pimpl->getNickname() }; + } + else + { + throw std::runtime_error(R"ex(Dog::getNickname is not implemented)ex"); + } + } + + service::AwaitableScalar> getBarkVolume(service::FieldParams&& params) const final + { + if constexpr (methods::DogHas::getBarkVolumeWithParams) + { + return { _pimpl->getBarkVolume(std::move(params)) }; + } + else if constexpr (methods::DogHas::getBarkVolume) + { + return { _pimpl->getBarkVolume() }; + } + else + { + throw std::runtime_error(R"ex(Dog::getBarkVolume is not implemented)ex"); + } + } + + service::AwaitableScalar getDoesKnowCommand(service::FieldParams&& params, DogCommand&& dogCommandArg) const final + { + if constexpr (methods::DogHas::getDoesKnowCommandWithParams) + { + return { _pimpl->getDoesKnowCommand(std::move(params), std::move(dogCommandArg)) }; + } + else if constexpr (methods::DogHas::getDoesKnowCommand) + { + return { _pimpl->getDoesKnowCommand(std::move(dogCommandArg)) }; + } + else + { + throw std::runtime_error(R"ex(Dog::getDoesKnowCommand is not implemented)ex"); + } + } + + service::AwaitableScalar getIsHousetrained(service::FieldParams&& params, std::optional&& atOtherHomesArg) const final + { + if constexpr (methods::DogHas::getIsHousetrainedWithParams) + { + return { _pimpl->getIsHousetrained(std::move(params), std::move(atOtherHomesArg)) }; + } + else if constexpr (methods::DogHas::getIsHousetrained) + { + return { _pimpl->getIsHousetrained(std::move(atOtherHomesArg)) }; + } + else + { + throw std::runtime_error(R"ex(Dog::getIsHousetrained is not implemented)ex"); + } + } + + service::AwaitableObject> getOwner(service::FieldParams&& params) const final + { + if constexpr (methods::DogHas::getOwnerWithParams) + { + return { _pimpl->getOwner(std::move(params)) }; + } + else if constexpr (methods::DogHas::getOwner) + { + return { _pimpl->getOwner() }; + } + else + { + throw std::runtime_error(R"ex(Dog::getOwner is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::DogHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::DogHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Dog(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Pet; + + // Unions which include this type + friend CatOrDog; + friend DogOrHuman; + + template + static constexpr bool implements() noexcept + { + return implements::DogIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Dog(std::shared_ptr pimpl) noexcept + : Dog { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::validation::object + +#endif // DOGOBJECT_H diff --git a/samples/validation/schema/DogOrHumanObject.cpp b/samples/validation/schema/DogOrHumanObject.cpp new file mode 100644 index 00000000..1fac2c21 --- /dev/null +++ b/samples/validation/schema/DogOrHumanObject.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "DogOrHumanObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +DogOrHuman::DogOrHuman(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void DogOrHuman::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void DogOrHuman::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddDogOrHumanDetails(const std::shared_ptr& typeDogOrHuman, const std::shared_ptr& schema) +{ + typeDogOrHuman->AddPossibleTypes({ + schema->LookupType(R"gql(Dog)gql"sv), + schema->LookupType(R"gql(Human)gql"sv) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/DogOrHumanObject.h b/samples/validation/schema/DogOrHumanObject.h new file mode 100644 index 00000000..917ce489 --- /dev/null +++ b/samples/validation/schema/DogOrHumanObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef DOGORHUMANOBJECT_H +#define DOGORHUMANOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { + +class DogOrHuman + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + DogOrHuman(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + DogOrHuman(std::shared_ptr pimpl) noexcept + : DogOrHuman { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "DogOrHuman is not implemented"); + } +}; + +} // namespace graphql::validation::object + +#endif // DOGORHUMANOBJECT_H diff --git a/samples/validation/schema/HumanObject.cpp b/samples/validation/schema/HumanObject.cpp new file mode 100644 index 00000000..cf243e29 --- /dev/null +++ b/samples/validation/schema/HumanObject.cpp @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "HumanObject.h" +#include "PetObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Human::Human(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Human::getTypeNames() const noexcept +{ + return { + R"gql(Sentient)gql"sv, + R"gql(DogOrHuman)gql"sv, + R"gql(HumanOrAlien)gql"sv, + R"gql(Human)gql"sv + }; +} + +service::ResolverMap Human::getResolvers() const noexcept +{ + return { + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(pets)gql"sv, [this](service::ResolverParams&& params) { return resolvePets(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void Human::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Human::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Human::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Human::resolvePets(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getPets(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Human::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Human)gql" }, std::move(params)); +} + +} // namespace object + +void AddHumanDetails(const std::shared_ptr& typeHuman, const std::shared_ptr& schema) +{ + typeHuman->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Sentient)gql"sv)) + }); + typeHuman->AddFields({ + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(pets)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Pet)gql"sv))))) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/HumanObject.h b/samples/validation/schema/HumanObject.h new file mode 100644 index 00000000..948e3d07 --- /dev/null +++ b/samples/validation/schema/HumanObject.h @@ -0,0 +1,175 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef HUMANOBJECT_H +#define HUMANOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { +namespace implements { + +template +concept HumanIs = std::is_same_v || std::is_same_v || std::is_same_v; + +} // namespace implements + +namespace methods::HumanHas { + +template +concept getNameWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getName(std::move(params)) } }; +}; + +template +concept getName = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getName() } }; +}; + +template +concept getPetsWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject>> { impl.getPets(std::move(params)) } }; +}; + +template +concept getPets = requires (TImpl impl) +{ + { service::AwaitableObject>> { impl.getPets() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::HumanHas + +class Human + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolvePets(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getName(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject>> getPets(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName(service::FieldParams&& params) const final + { + if constexpr (methods::HumanHas::getNameWithParams) + { + return { _pimpl->getName(std::move(params)) }; + } + else if constexpr (methods::HumanHas::getName) + { + return { _pimpl->getName() }; + } + else + { + throw std::runtime_error(R"ex(Human::getName is not implemented)ex"); + } + } + + service::AwaitableObject>> getPets(service::FieldParams&& params) const final + { + if constexpr (methods::HumanHas::getPetsWithParams) + { + return { _pimpl->getPets(std::move(params)) }; + } + else if constexpr (methods::HumanHas::getPets) + { + return { _pimpl->getPets() }; + } + else + { + throw std::runtime_error(R"ex(Human::getPets is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::HumanHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::HumanHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Human(std::unique_ptr&& pimpl) noexcept; + + // Interfaces which this type implements + friend Sentient; + + // Unions which include this type + friend DogOrHuman; + friend HumanOrAlien; + + template + static constexpr bool implements() noexcept + { + return implements::HumanIs; + } + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Human(std::shared_ptr pimpl) noexcept + : Human { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::validation::object + +#endif // HUMANOBJECT_H diff --git a/samples/validation/schema/HumanOrAlienObject.cpp b/samples/validation/schema/HumanOrAlienObject.cpp new file mode 100644 index 00000000..cb6f6a2a --- /dev/null +++ b/samples/validation/schema/HumanOrAlienObject.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "HumanOrAlienObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +HumanOrAlien::HumanOrAlien(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void HumanOrAlien::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void HumanOrAlien::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddHumanOrAlienDetails(const std::shared_ptr& typeHumanOrAlien, const std::shared_ptr& schema) +{ + typeHumanOrAlien->AddPossibleTypes({ + schema->LookupType(R"gql(Human)gql"sv), + schema->LookupType(R"gql(Alien)gql"sv) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/HumanOrAlienObject.h b/samples/validation/schema/HumanOrAlienObject.h new file mode 100644 index 00000000..1f1e9297 --- /dev/null +++ b/samples/validation/schema/HumanOrAlienObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef HUMANORALIENOBJECT_H +#define HUMANORALIENOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { + +class HumanOrAlien + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + HumanOrAlien(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + HumanOrAlien(std::shared_ptr pimpl) noexcept + : HumanOrAlien { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "HumanOrAlien is not implemented"); + } +}; + +} // namespace graphql::validation::object + +#endif // HUMANORALIENOBJECT_H diff --git a/samples/validation/schema/MessageObject.cpp b/samples/validation/schema/MessageObject.cpp new file mode 100644 index 00000000..4fddf185 --- /dev/null +++ b/samples/validation/schema/MessageObject.cpp @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "MessageObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Message::Message(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Message::getTypeNames() const noexcept +{ + return { + R"gql(Message)gql"sv + }; +} + +service::ResolverMap Message::getResolvers() const noexcept +{ + return { + { R"gql(body)gql"sv, [this](service::ResolverParams&& params) { return resolveBody(std::move(params)); } }, + { R"gql(sender)gql"sv, [this](service::ResolverParams&& params) { return resolveSender(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void Message::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Message::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Message::resolveBody(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getBody(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Message::resolveSender(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getSender(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Message::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Message)gql" }, std::move(params)); +} + +} // namespace object + +void AddMessageDetails(const std::shared_ptr& typeMessage, const std::shared_ptr& schema) +{ + typeMessage->AddFields({ + schema::Field::Make(R"gql(body)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(sender)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/MessageObject.h b/samples/validation/schema/MessageObject.h new file mode 100644 index 00000000..05e56a38 --- /dev/null +++ b/samples/validation/schema/MessageObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef MESSAGEOBJECT_H +#define MESSAGEOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { +namespace methods::MessageHas { + +template +concept getBodyWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar> { impl.getBody(std::move(params)) } }; +}; + +template +concept getBody = requires (TImpl impl) +{ + { service::AwaitableScalar> { impl.getBody() } }; +}; + +template +concept getSenderWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getSender(std::move(params)) } }; +}; + +template +concept getSender = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getSender() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::MessageHas + +class Message + : public service::Object +{ +private: + service::AwaitableResolver resolveBody(service::ResolverParams&& params) const; + service::AwaitableResolver resolveSender(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar> getBody(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getSender(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar> getBody(service::FieldParams&& params) const final + { + if constexpr (methods::MessageHas::getBodyWithParams) + { + return { _pimpl->getBody(std::move(params)) }; + } + else if constexpr (methods::MessageHas::getBody) + { + return { _pimpl->getBody() }; + } + else + { + throw std::runtime_error(R"ex(Message::getBody is not implemented)ex"); + } + } + + service::AwaitableScalar getSender(service::FieldParams&& params) const final + { + if constexpr (methods::MessageHas::getSenderWithParams) + { + return { _pimpl->getSender(std::move(params)) }; + } + else if constexpr (methods::MessageHas::getSender) + { + return { _pimpl->getSender() }; + } + else + { + throw std::runtime_error(R"ex(Message::getSender is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MessageHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MessageHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Message(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Message(std::shared_ptr pimpl) noexcept + : Message { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::validation::object + +#endif // MESSAGEOBJECT_H diff --git a/samples/validation/schema/MutateDogResultObject.cpp b/samples/validation/schema/MutateDogResultObject.cpp new file mode 100644 index 00000000..44f9cd26 --- /dev/null +++ b/samples/validation/schema/MutateDogResultObject.cpp @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "MutateDogResultObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +MutateDogResult::MutateDogResult(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames MutateDogResult::getTypeNames() const noexcept +{ + return { + R"gql(MutateDogResult)gql"sv + }; +} + +service::ResolverMap MutateDogResult::getResolvers() const noexcept +{ + return { + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void MutateDogResult::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void MutateDogResult::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver MutateDogResult::resolveId(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getId(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver MutateDogResult::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(MutateDogResult)gql" }, std::move(params)); +} + +} // namespace object + +void AddMutateDogResultDetails(const std::shared_ptr& typeMutateDogResult, const std::shared_ptr& schema) +{ + typeMutateDogResult->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/MutateDogResultObject.h b/samples/validation/schema/MutateDogResultObject.h new file mode 100644 index 00000000..dddb50e3 --- /dev/null +++ b/samples/validation/schema/MutateDogResultObject.h @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef MUTATEDOGRESULTOBJECT_H +#define MUTATEDOGRESULTOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { +namespace methods::MutateDogResultHas { + +template +concept getIdWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getId(std::move(params)) } }; +}; + +template +concept getId = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getId() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::MutateDogResultHas + +class MutateDogResult + : public service::Object +{ +private: + service::AwaitableResolver resolveId(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableScalar getId(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getId(service::FieldParams&& params) const final + { + if constexpr (methods::MutateDogResultHas::getIdWithParams) + { + return { _pimpl->getId(std::move(params)) }; + } + else if constexpr (methods::MutateDogResultHas::getId) + { + return { _pimpl->getId() }; + } + else + { + throw std::runtime_error(R"ex(MutateDogResult::getId is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MutateDogResultHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MutateDogResultHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + MutateDogResult(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + MutateDogResult(std::shared_ptr pimpl) noexcept + : MutateDogResult { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::validation::object + +#endif // MUTATEDOGRESULTOBJECT_H diff --git a/samples/validation/schema/MutationObject.cpp b/samples/validation/schema/MutationObject.cpp new file mode 100644 index 00000000..9a6a7cd2 --- /dev/null +++ b/samples/validation/schema/MutationObject.cpp @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "MutationObject.h" +#include "MutateDogResultObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Mutation::Mutation(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Mutation::getTypeNames() const noexcept +{ + return { + R"gql(Mutation)gql"sv + }; +} + +service::ResolverMap Mutation::getResolvers() const noexcept +{ + return { + { R"gql(mutateDog)gql"sv, [this](service::ResolverParams&& params) { return resolveMutateDog(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } } + }; +} + +void Mutation::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Mutation::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Mutation::resolveMutateDog(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->applyMutateDog(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Mutation::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Mutation)gql" }, std::move(params)); +} + +} // namespace object + +void AddMutationDetails(const std::shared_ptr& typeMutation, const std::shared_ptr& schema) +{ + typeMutation->AddFields({ + schema::Field::Make(R"gql(mutateDog)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(MutateDogResult)gql"sv)) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/MutationObject.h b/samples/validation/schema/MutationObject.h new file mode 100644 index 00000000..7096c006 --- /dev/null +++ b/samples/validation/schema/MutationObject.h @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef MUTATIONOBJECT_H +#define MUTATIONOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { +namespace methods::MutationHas { + +template +concept applyMutateDogWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.applyMutateDog(std::move(params)) } }; +}; + +template +concept applyMutateDog = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.applyMutateDog() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::MutationHas + +class Mutation + : public service::Object +{ +private: + service::AwaitableResolver resolveMutateDog(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> applyMutateDog(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> applyMutateDog(service::FieldParams&& params) const final + { + if constexpr (methods::MutationHas::applyMutateDogWithParams) + { + return { _pimpl->applyMutateDog(std::move(params)) }; + } + else if constexpr (methods::MutationHas::applyMutateDog) + { + return { _pimpl->applyMutateDog() }; + } + else + { + throw std::runtime_error(R"ex(Mutation::applyMutateDog is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MutationHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::MutationHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Mutation(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Mutation(std::shared_ptr pimpl) noexcept + : Mutation { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::validation::object + +#endif // MUTATIONOBJECT_H diff --git a/samples/validation/schema/NodeObject.cpp b/samples/validation/schema/NodeObject.cpp new file mode 100644 index 00000000..3db93efb --- /dev/null +++ b/samples/validation/schema/NodeObject.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "NodeObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Node::Node(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void Node::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Node::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddNodeDetails(const std::shared_ptr& typeNode, const std::shared_ptr& schema) +{ + typeNode->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/NodeObject.h b/samples/validation/schema/NodeObject.h new file mode 100644 index 00000000..3075e854 --- /dev/null +++ b/samples/validation/schema/NodeObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef NODEOBJECT_H +#define NODEOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { + +class Node + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + Node(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Node(std::shared_ptr pimpl) noexcept + : Node { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "Node is not implemented"); + } +}; + +} // namespace graphql::validation::object + +#endif // NODEOBJECT_H diff --git a/samples/validation/schema/PetObject.cpp b/samples/validation/schema/PetObject.cpp new file mode 100644 index 00000000..106161c6 --- /dev/null +++ b/samples/validation/schema/PetObject.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "PetObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Pet::Pet(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void Pet::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Pet::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddPetDetails(const std::shared_ptr& typePet, const std::shared_ptr& schema) +{ + typePet->AddFields({ + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/PetObject.h b/samples/validation/schema/PetObject.h new file mode 100644 index 00000000..bf30ed00 --- /dev/null +++ b/samples/validation/schema/PetObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef PETOBJECT_H +#define PETOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { + +class Pet + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + Pet(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Pet(std::shared_ptr pimpl) noexcept + : Pet { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "Pet is not implemented"); + } +}; + +} // namespace graphql::validation::object + +#endif // PETOBJECT_H diff --git a/samples/validation/schema/QueryObject.cpp b/samples/validation/schema/QueryObject.cpp new file mode 100644 index 00000000..80f0caa2 --- /dev/null +++ b/samples/validation/schema/QueryObject.cpp @@ -0,0 +1,174 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "QueryObject.h" +#include "DogObject.h" +#include "HumanObject.h" +#include "PetObject.h" +#include "CatOrDogObject.h" +#include "ArgumentsObject.h" +#include "ResourceObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Query::Query(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Query::getTypeNames() const noexcept +{ + return { + R"gql(Query)gql"sv + }; +} + +service::ResolverMap Query::getResolvers() const noexcept +{ + return { + { R"gql(dog)gql"sv, [this](service::ResolverParams&& params) { return resolveDog(std::move(params)); } }, + { R"gql(pet)gql"sv, [this](service::ResolverParams&& params) { return resolvePet(std::move(params)); } }, + { R"gql(human)gql"sv, [this](service::ResolverParams&& params) { return resolveHuman(std::move(params)); } }, + { R"gql(findDog)gql"sv, [this](service::ResolverParams&& params) { return resolveFindDog(std::move(params)); } }, + { R"gql(catOrDog)gql"sv, [this](service::ResolverParams&& params) { return resolveCatOrDog(std::move(params)); } }, + { R"gql(resource)gql"sv, [this](service::ResolverParams&& params) { return resolveResource(std::move(params)); } }, + { R"gql(arguments)gql"sv, [this](service::ResolverParams&& params) { return resolveArguments(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(booleanList)gql"sv, [this](service::ResolverParams&& params) { return resolveBooleanList(std::move(params)); } } + }; +} + +void Query::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Query::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Query::resolveDog(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getDog(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Query::resolveHuman(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getHuman(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Query::resolvePet(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getPet(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Query::resolveCatOrDog(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getCatOrDog(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Query::resolveArguments(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getArguments(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Query::resolveResource(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getResource(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Query::resolveFindDog(service::ResolverParams&& params) const +{ + auto argComplex = service::ModifiedArgument::require("complex", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getFindDog(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argComplex)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Query::resolveBooleanList(service::ResolverParams&& params) const +{ + auto argBooleanListArg = service::ModifiedArgument::require("booleanListArg", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getBooleanList(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argBooleanListArg)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Query::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Query)gql" }, std::move(params)); +} + +} // namespace object + +void AddQueryDetails(const std::shared_ptr& typeQuery, const std::shared_ptr& schema) +{ + typeQuery->AddFields({ + schema::Field::Make(R"gql(dog)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Dog)gql"sv)), + schema::Field::Make(R"gql(human)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Human)gql"sv)), + schema::Field::Make(R"gql(pet)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Pet)gql"sv)), + schema::Field::Make(R"gql(catOrDog)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(CatOrDog)gql"sv)), + schema::Field::Make(R"gql(arguments)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Arguments)gql"sv)), + schema::Field::Make(R"gql(resource)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Resource)gql"sv)), + schema::Field::Make(R"gql(findDog)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Dog)gql"sv), { + schema::InputValue::Make(R"gql(complex)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ComplexInput)gql"sv), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(booleanList)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(Boolean)gql"sv), { + schema::InputValue::Make(R"gql(booleanListArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))), R"gql()gql"sv) + }) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/QueryObject.h b/samples/validation/schema/QueryObject.h new file mode 100644 index 00000000..d2935dc0 --- /dev/null +++ b/samples/validation/schema/QueryObject.h @@ -0,0 +1,335 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef QUERYOBJECT_H +#define QUERYOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { +namespace methods::QueryHas { + +template +concept getDogWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getDog(std::move(params)) } }; +}; + +template +concept getDog = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getDog() } }; +}; + +template +concept getHumanWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getHuman(std::move(params)) } }; +}; + +template +concept getHuman = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getHuman() } }; +}; + +template +concept getPetWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getPet(std::move(params)) } }; +}; + +template +concept getPet = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getPet() } }; +}; + +template +concept getCatOrDogWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getCatOrDog(std::move(params)) } }; +}; + +template +concept getCatOrDog = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getCatOrDog() } }; +}; + +template +concept getArgumentsWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getArguments(std::move(params)) } }; +}; + +template +concept getArguments = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getArguments() } }; +}; + +template +concept getResourceWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getResource(std::move(params)) } }; +}; + +template +concept getResource = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getResource() } }; +}; + +template +concept getFindDogWithParams = requires (TImpl impl, service::FieldParams params, std::optional complexArg) +{ + { service::AwaitableObject> { impl.getFindDog(std::move(params), std::move(complexArg)) } }; +}; + +template +concept getFindDog = requires (TImpl impl, std::optional complexArg) +{ + { service::AwaitableObject> { impl.getFindDog(std::move(complexArg)) } }; +}; + +template +concept getBooleanListWithParams = requires (TImpl impl, service::FieldParams params, std::optional> booleanListArgArg) +{ + { service::AwaitableScalar> { impl.getBooleanList(std::move(params), std::move(booleanListArgArg)) } }; +}; + +template +concept getBooleanList = requires (TImpl impl, std::optional> booleanListArgArg) +{ + { service::AwaitableScalar> { impl.getBooleanList(std::move(booleanListArgArg)) } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::QueryHas + +class Query + : public service::Object +{ +private: + service::AwaitableResolver resolveDog(service::ResolverParams&& params) const; + service::AwaitableResolver resolveHuman(service::ResolverParams&& params) const; + service::AwaitableResolver resolvePet(service::ResolverParams&& params) const; + service::AwaitableResolver resolveCatOrDog(service::ResolverParams&& params) const; + service::AwaitableResolver resolveArguments(service::ResolverParams&& params) const; + service::AwaitableResolver resolveResource(service::ResolverParams&& params) const; + service::AwaitableResolver resolveFindDog(service::ResolverParams&& params) const; + service::AwaitableResolver resolveBooleanList(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getDog(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject> getHuman(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject> getPet(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject> getCatOrDog(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject> getArguments(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject> getResource(service::FieldParams&& params) const = 0; + virtual service::AwaitableObject> getFindDog(service::FieldParams&& params, std::optional&& complexArg) const = 0; + virtual service::AwaitableScalar> getBooleanList(service::FieldParams&& params, std::optional>&& booleanListArgArg) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getDog(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getDogWithParams) + { + return { _pimpl->getDog(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getDog) + { + return { _pimpl->getDog() }; + } + else + { + throw std::runtime_error(R"ex(Query::getDog is not implemented)ex"); + } + } + + service::AwaitableObject> getHuman(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getHumanWithParams) + { + return { _pimpl->getHuman(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getHuman) + { + return { _pimpl->getHuman() }; + } + else + { + throw std::runtime_error(R"ex(Query::getHuman is not implemented)ex"); + } + } + + service::AwaitableObject> getPet(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getPetWithParams) + { + return { _pimpl->getPet(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getPet) + { + return { _pimpl->getPet() }; + } + else + { + throw std::runtime_error(R"ex(Query::getPet is not implemented)ex"); + } + } + + service::AwaitableObject> getCatOrDog(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getCatOrDogWithParams) + { + return { _pimpl->getCatOrDog(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getCatOrDog) + { + return { _pimpl->getCatOrDog() }; + } + else + { + throw std::runtime_error(R"ex(Query::getCatOrDog is not implemented)ex"); + } + } + + service::AwaitableObject> getArguments(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getArgumentsWithParams) + { + return { _pimpl->getArguments(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getArguments) + { + return { _pimpl->getArguments() }; + } + else + { + throw std::runtime_error(R"ex(Query::getArguments is not implemented)ex"); + } + } + + service::AwaitableObject> getResource(service::FieldParams&& params) const final + { + if constexpr (methods::QueryHas::getResourceWithParams) + { + return { _pimpl->getResource(std::move(params)) }; + } + else if constexpr (methods::QueryHas::getResource) + { + return { _pimpl->getResource() }; + } + else + { + throw std::runtime_error(R"ex(Query::getResource is not implemented)ex"); + } + } + + service::AwaitableObject> getFindDog(service::FieldParams&& params, std::optional&& complexArg) const final + { + if constexpr (methods::QueryHas::getFindDogWithParams) + { + return { _pimpl->getFindDog(std::move(params), std::move(complexArg)) }; + } + else if constexpr (methods::QueryHas::getFindDog) + { + return { _pimpl->getFindDog(std::move(complexArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getFindDog is not implemented)ex"); + } + } + + service::AwaitableScalar> getBooleanList(service::FieldParams&& params, std::optional>&& booleanListArgArg) const final + { + if constexpr (methods::QueryHas::getBooleanListWithParams) + { + return { _pimpl->getBooleanList(std::move(params), std::move(booleanListArgArg)) }; + } + else if constexpr (methods::QueryHas::getBooleanList) + { + return { _pimpl->getBooleanList(std::move(booleanListArgArg)) }; + } + else + { + throw std::runtime_error(R"ex(Query::getBooleanList is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::QueryHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::QueryHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Query(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Query(std::shared_ptr pimpl) noexcept + : Query { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::validation::object + +#endif // QUERYOBJECT_H diff --git a/samples/validation/schema/ResourceObject.cpp b/samples/validation/schema/ResourceObject.cpp new file mode 100644 index 00000000..4bea15ce --- /dev/null +++ b/samples/validation/schema/ResourceObject.cpp @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "ResourceObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Resource::Resource(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void Resource::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Resource::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddResourceDetails(const std::shared_ptr& typeResource, const std::shared_ptr& schema) +{ + typeResource->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) + }); + typeResource->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv))), + schema::Field::Make(R"gql(url)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/ResourceObject.h b/samples/validation/schema/ResourceObject.h new file mode 100644 index 00000000..1fa71284 --- /dev/null +++ b/samples/validation/schema/ResourceObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef RESOURCEOBJECT_H +#define RESOURCEOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { + +class Resource + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + Resource(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Resource(std::shared_ptr pimpl) noexcept + : Resource { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "Resource is not implemented"); + } +}; + +} // namespace graphql::validation::object + +#endif // RESOURCEOBJECT_H diff --git a/samples/validation/schema/SentientObject.cpp b/samples/validation/schema/SentientObject.cpp new file mode 100644 index 00000000..656ce774 --- /dev/null +++ b/samples/validation/schema/SentientObject.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "SentientObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Sentient::Sentient(std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +void Sentient::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Sentient::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +} // namespace object + +void AddSentientDetails(const std::shared_ptr& typeSentient, const std::shared_ptr& schema) +{ + typeSentient->AddFields({ + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/SentientObject.h b/samples/validation/schema/SentientObject.h new file mode 100644 index 00000000..8569fc20 --- /dev/null +++ b/samples/validation/schema/SentientObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef SENTIENTOBJECT_H +#define SENTIENTOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { + +class Sentient + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + Sentient(std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Sentient(std::shared_ptr pimpl) noexcept + : Sentient { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements(), "Sentient is not implemented"); + } +}; + +} // namespace graphql::validation::object + +#endif // SENTIENTOBJECT_H diff --git a/samples/validation/schema/SubscriptionObject.cpp b/samples/validation/schema/SubscriptionObject.cpp new file mode 100644 index 00000000..1e7ae9d8 --- /dev/null +++ b/samples/validation/schema/SubscriptionObject.cpp @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "SubscriptionObject.h" +#include "MessageObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::validation { +namespace object { + +Subscription::Subscription(std::unique_ptr&& pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} + +service::TypeNames Subscription::getTypeNames() const noexcept +{ + return { + R"gql(Subscription)gql"sv + }; +} + +service::ResolverMap Subscription::getResolvers() const noexcept +{ + return { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(newMessage)gql"sv, [this](service::ResolverParams&& params) { return resolveNewMessage(std::move(params)); } }, + { R"gql(disallowedSecondRootField)gql"sv, [this](service::ResolverParams&& params) { return resolveDisallowedSecondRootField(std::move(params)); } } + }; +} + +void Subscription::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void Subscription::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} + +service::AwaitableResolver Subscription::resolveNewMessage(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getNewMessage(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Subscription::resolveDisallowedSecondRootField(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto directives = std::move(params.fieldDirectives); + auto result = _pimpl->getDisallowedSecondRootField(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Subscription::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(Subscription)gql" }, std::move(params)); +} + +} // namespace object + +void AddSubscriptionDetails(const std::shared_ptr& typeSubscription, const std::shared_ptr& schema) +{ + typeSubscription->AddFields({ + schema::Field::Make(R"gql(newMessage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Message)gql"sv))), + schema::Field::Make(R"gql(disallowedSecondRootField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))) + }); +} + +} // namespace graphql::validation diff --git a/samples/validation/schema/SubscriptionObject.h b/samples/validation/schema/SubscriptionObject.h new file mode 100644 index 00000000..4474734e --- /dev/null +++ b/samples/validation/schema/SubscriptionObject.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef SUBSCRIPTIONOBJECT_H +#define SUBSCRIPTIONOBJECT_H + +#include "ValidationSchema.h" + +namespace graphql::validation::object { +namespace methods::SubscriptionHas { + +template +concept getNewMessageWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableObject> { impl.getNewMessage(std::move(params)) } }; +}; + +template +concept getNewMessage = requires (TImpl impl) +{ + { service::AwaitableObject> { impl.getNewMessage() } }; +}; + +template +concept getDisallowedSecondRootFieldWithParams = requires (TImpl impl, service::FieldParams params) +{ + { service::AwaitableScalar { impl.getDisallowedSecondRootField(std::move(params)) } }; +}; + +template +concept getDisallowedSecondRootField = requires (TImpl impl) +{ + { service::AwaitableScalar { impl.getDisallowedSecondRootField() } }; +}; + +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +} // namespace methods::SubscriptionHas + +class Subscription + : public service::Object +{ +private: + service::AwaitableResolver resolveNewMessage(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDisallowedSecondRootField(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + + virtual service::AwaitableObject> getNewMessage(service::FieldParams&& params) const = 0; + virtual service::AwaitableScalar getDisallowedSecondRootField(service::FieldParams&& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableObject> getNewMessage(service::FieldParams&& params) const final + { + if constexpr (methods::SubscriptionHas::getNewMessageWithParams) + { + return { _pimpl->getNewMessage(std::move(params)) }; + } + else if constexpr (methods::SubscriptionHas::getNewMessage) + { + return { _pimpl->getNewMessage() }; + } + else + { + throw std::runtime_error(R"ex(Subscription::getNewMessage is not implemented)ex"); + } + } + + service::AwaitableScalar getDisallowedSecondRootField(service::FieldParams&& params) const final + { + if constexpr (methods::SubscriptionHas::getDisallowedSecondRootFieldWithParams) + { + return { _pimpl->getDisallowedSecondRootField(std::move(params)) }; + } + else if constexpr (methods::SubscriptionHas::getDisallowedSecondRootField) + { + return { _pimpl->getDisallowedSecondRootField() }; + } + else + { + throw std::runtime_error(R"ex(Subscription::getDisallowedSecondRootField is not implemented)ex"); + } + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::SubscriptionHas::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::SubscriptionHas::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } + + private: + const std::shared_ptr _pimpl; + }; + + Subscription(std::unique_ptr&& pimpl) noexcept; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + Subscription(std::shared_ptr pimpl) noexcept + : Subscription { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; + +} // namespace graphql::validation::object + +#endif // SUBSCRIPTIONOBJECT_H diff --git a/samples/validation/schema/ValidationSchema.cpp b/samples/validation/schema/ValidationSchema.cpp new file mode 100644 index 00000000..8245eead --- /dev/null +++ b/samples/validation/schema/ValidationSchema.cpp @@ -0,0 +1,261 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "QueryObject.h" +#include "MutationObject.h" +#include "SubscriptionObject.h" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql { +namespace service { + +static const std::array s_namesDogCommand = { + R"gql(SIT)gql"sv, + R"gql(DOWN)gql"sv, + R"gql(HEEL)gql"sv +}; + +template <> +validation::DogCommand ModifiedArgument::convert(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid DogCommand value)ex" } }; + } + + const auto itr = std::find(s_namesDogCommand.cbegin(), s_namesDogCommand.cend(), value.get()); + + if (itr == s_namesDogCommand.cend()) + { + throw service::schema_exception { { R"ex(not a valid DogCommand value)ex" } }; + } + + return static_cast(itr - s_namesDogCommand.cbegin()); +} + +template <> +service::AwaitableResolver ModifiedResult::convert(service::AwaitableScalar result, ResolverParams params) +{ + return resolve(std::move(result), std::move(params), + [](validation::DogCommand value, const ResolverParams&) + { + response::Value result(response::Type::EnumValue); + + result.set(std::string { s_namesDogCommand[static_cast(value)] }); + + return result; + }); +} + +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid DogCommand value)ex" } }; + } + + const auto itr = std::find(s_namesDogCommand.cbegin(), s_namesDogCommand.cend(), value.get()); + + if (itr == s_namesDogCommand.cend()) + { + throw service::schema_exception { { R"ex(not a valid DogCommand value)ex" } }; + } +} + +static const std::array s_namesCatCommand = { + R"gql(JUMP)gql"sv +}; + +template <> +validation::CatCommand ModifiedArgument::convert(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid CatCommand value)ex" } }; + } + + const auto itr = std::find(s_namesCatCommand.cbegin(), s_namesCatCommand.cend(), value.get()); + + if (itr == s_namesCatCommand.cend()) + { + throw service::schema_exception { { R"ex(not a valid CatCommand value)ex" } }; + } + + return static_cast(itr - s_namesCatCommand.cbegin()); +} + +template <> +service::AwaitableResolver ModifiedResult::convert(service::AwaitableScalar result, ResolverParams params) +{ + return resolve(std::move(result), std::move(params), + [](validation::CatCommand value, const ResolverParams&) + { + response::Value result(response::Type::EnumValue); + + result.set(std::string { s_namesCatCommand[static_cast(value)] }); + + return result; + }); +} + +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid CatCommand value)ex" } }; + } + + const auto itr = std::find(s_namesCatCommand.cbegin(), s_namesCatCommand.cend(), value.get()); + + if (itr == s_namesCatCommand.cend()) + { + throw service::schema_exception { { R"ex(not a valid CatCommand value)ex" } }; + } +} + +template <> +validation::ComplexInput ModifiedArgument::convert(const response::Value& value) +{ + auto valueName = service::ModifiedArgument::require("name", value); + auto valueOwner = service::ModifiedArgument::require("owner", value); + + return { + std::move(valueName), + std::move(valueOwner) + }; +} + +} // namespace service + +namespace validation { + +Operations::Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription) + : service::Request({ + { "query", query }, + { "mutation", mutation }, + { "subscription", subscription } + }, GetSchema()) + , _query(std::move(query)) + , _mutation(std::move(mutation)) + , _subscription(std::move(subscription)) +{ +} + +void AddTypesToSchema(const std::shared_ptr& schema) +{ + auto typeDogCommand = schema::EnumType::Make(R"gql(DogCommand)gql"sv, R"md()md"sv); + schema->AddType(R"gql(DogCommand)gql"sv, typeDogCommand); + auto typeCatCommand = schema::EnumType::Make(R"gql(CatCommand)gql"sv, R"md()md"sv); + schema->AddType(R"gql(CatCommand)gql"sv, typeCatCommand); + auto typeComplexInput = schema::InputObjectType::Make(R"gql(ComplexInput)gql"sv, R"md()md"sv); + schema->AddType(R"gql(ComplexInput)gql"sv, typeComplexInput); + auto typeSentient = schema::InterfaceType::Make(R"gql(Sentient)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Sentient)gql"sv, typeSentient); + auto typePet = schema::InterfaceType::Make(R"gql(Pet)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Pet)gql"sv, typePet); + auto typeNode = schema::InterfaceType::Make(R"gql(Node)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Node)gql"sv, typeNode); + auto typeResource = schema::InterfaceType::Make(R"gql(Resource)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Resource)gql"sv, typeResource); + auto typeCatOrDog = schema::UnionType::Make(R"gql(CatOrDog)gql"sv, R"md()md"sv); + schema->AddType(R"gql(CatOrDog)gql"sv, typeCatOrDog); + auto typeDogOrHuman = schema::UnionType::Make(R"gql(DogOrHuman)gql"sv, R"md()md"sv); + schema->AddType(R"gql(DogOrHuman)gql"sv, typeDogOrHuman); + auto typeHumanOrAlien = schema::UnionType::Make(R"gql(HumanOrAlien)gql"sv, R"md()md"sv); + schema->AddType(R"gql(HumanOrAlien)gql"sv, typeHumanOrAlien); + auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Query)gql"sv, typeQuery); + auto typeDog = schema::ObjectType::Make(R"gql(Dog)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Dog)gql"sv, typeDog); + auto typeAlien = schema::ObjectType::Make(R"gql(Alien)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Alien)gql"sv, typeAlien); + auto typeHuman = schema::ObjectType::Make(R"gql(Human)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Human)gql"sv, typeHuman); + auto typeCat = schema::ObjectType::Make(R"gql(Cat)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Cat)gql"sv, typeCat); + auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Mutation)gql"sv, typeMutation); + auto typeMutateDogResult = schema::ObjectType::Make(R"gql(MutateDogResult)gql"sv, R"md()md"sv); + schema->AddType(R"gql(MutateDogResult)gql"sv, typeMutateDogResult); + auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Subscription)gql"sv, typeSubscription); + auto typeMessage = schema::ObjectType::Make(R"gql(Message)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Message)gql"sv, typeMessage); + auto typeArguments = schema::ObjectType::Make(R"gql(Arguments)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Arguments)gql"sv, typeArguments); + + typeDogCommand->AddEnumValues({ + { service::s_namesDogCommand[static_cast(validation::DogCommand::SIT)], R"md()md"sv, std::nullopt }, + { service::s_namesDogCommand[static_cast(validation::DogCommand::DOWN)], R"md()md"sv, std::nullopt }, + { service::s_namesDogCommand[static_cast(validation::DogCommand::HEEL)], R"md()md"sv, std::nullopt } + }); + typeCatCommand->AddEnumValues({ + { service::s_namesCatCommand[static_cast(validation::CatCommand::JUMP)], R"md()md"sv, std::nullopt } + }); + + typeComplexInput->AddInputValues({ + schema::InputValue::Make(R"gql(name)gql"sv, R"md()md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql()gql"sv), + schema::InputValue::Make(R"gql(owner)gql"sv, R"md()md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql()gql"sv) + }); + + AddSentientDetails(typeSentient, schema); + AddPetDetails(typePet, schema); + AddNodeDetails(typeNode, schema); + AddResourceDetails(typeResource, schema); + + AddCatOrDogDetails(typeCatOrDog, schema); + AddDogOrHumanDetails(typeDogOrHuman, schema); + AddHumanOrAlienDetails(typeHumanOrAlien, schema); + + AddQueryDetails(typeQuery, schema); + AddDogDetails(typeDog, schema); + AddAlienDetails(typeAlien, schema); + AddHumanDetails(typeHuman, schema); + AddCatDetails(typeCat, schema); + AddMutationDetails(typeMutation, schema); + AddMutateDogResultDetails(typeMutateDogResult, schema); + AddSubscriptionDetails(typeSubscription, schema); + AddMessageDetails(typeMessage, schema); + AddArgumentsDetails(typeArguments, schema); + + schema->AddQueryType(typeQuery); + schema->AddMutationType(typeMutation); + schema->AddSubscriptionType(typeSubscription); +} + +std::shared_ptr GetSchema() +{ + static std::weak_ptr s_wpSchema; + auto schema = s_wpSchema.lock(); + + if (!schema) + { + schema = std::make_shared(true, R"md()md"sv); + introspection::AddTypesToSchema(schema); + AddTypesToSchema(schema); + s_wpSchema = schema; + } + + return schema; +} + +} // namespace validation +} // namespace graphql diff --git a/samples/validation/schema/ValidationSchema.h b/samples/validation/schema/ValidationSchema.h new file mode 100644 index 00000000..129ac91e --- /dev/null +++ b/samples/validation/schema/ValidationSchema.h @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef VALIDATIONSCHEMA_H +#define VALIDATIONSCHEMA_H + +#include "graphqlservice/internal/Schema.h" + +// Check if the library version is compatible with schemagen 4.0.0 +static_assert(graphql::internal::MajorVersion == 4, "regenerate with schemagen: major version mismatch"); +static_assert(graphql::internal::MinorVersion == 0, "regenerate with schemagen: minor version mismatch"); + +#include +#include +#include + +namespace graphql { +namespace validation { + +enum class DogCommand +{ + SIT, + DOWN, + HEEL +}; + +enum class CatCommand +{ + JUMP +}; + +struct ComplexInput +{ + std::optional name {}; + std::optional owner {}; +}; + +namespace object { + +class Sentient; +class Pet; +class Node; +class Resource; + +class CatOrDog; +class DogOrHuman; +class HumanOrAlien; + +class Query; +class Dog; +class Alien; +class Human; +class Cat; +class Mutation; +class MutateDogResult; +class Subscription; +class Message; +class Arguments; + +} // namespace object + +class Operations + : public service::Request +{ +public: + explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription); + + template + explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription) + : Operations { std::make_shared(std::move(query)), std::make_shared(std::move(mutation)), std::make_shared(std::move(subscription)) } + { + } + +private: + std::shared_ptr _query; + std::shared_ptr _mutation; + std::shared_ptr _subscription; +}; + +void AddSentientDetails(const std::shared_ptr& typeSentient, const std::shared_ptr& schema); +void AddPetDetails(const std::shared_ptr& typePet, const std::shared_ptr& schema); +void AddNodeDetails(const std::shared_ptr& typeNode, const std::shared_ptr& schema); +void AddResourceDetails(const std::shared_ptr& typeResource, const std::shared_ptr& schema); + +void AddCatOrDogDetails(const std::shared_ptr& typeCatOrDog, const std::shared_ptr& schema); +void AddDogOrHumanDetails(const std::shared_ptr& typeDogOrHuman, const std::shared_ptr& schema); +void AddHumanOrAlienDetails(const std::shared_ptr& typeHumanOrAlien, const std::shared_ptr& schema); + +void AddQueryDetails(const std::shared_ptr& typeQuery, const std::shared_ptr& schema); +void AddDogDetails(const std::shared_ptr& typeDog, const std::shared_ptr& schema); +void AddAlienDetails(const std::shared_ptr& typeAlien, const std::shared_ptr& schema); +void AddHumanDetails(const std::shared_ptr& typeHuman, const std::shared_ptr& schema); +void AddCatDetails(const std::shared_ptr& typeCat, const std::shared_ptr& schema); +void AddMutationDetails(const std::shared_ptr& typeMutation, const std::shared_ptr& schema); +void AddMutateDogResultDetails(const std::shared_ptr& typeMutateDogResult, const std::shared_ptr& schema); +void AddSubscriptionDetails(const std::shared_ptr& typeSubscription, const std::shared_ptr& schema); +void AddMessageDetails(const std::shared_ptr& typeMessage, const std::shared_ptr& schema); +void AddArgumentsDetails(const std::shared_ptr& typeArguments, const std::shared_ptr& schema); + +std::shared_ptr GetSchema(); + +} // namespace validation +} // namespace graphql + +#endif // VALIDATIONSCHEMA_H diff --git a/samples/validation/schema/schema.validation.graphql b/samples/validation/schema/schema.validation.graphql new file mode 100644 index 00000000..e1515c39 --- /dev/null +++ b/samples/validation/schema/schema.validation.graphql @@ -0,0 +1,132 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +"GraphQL validation [sample](https://spec.graphql.org/October2021/#example-19f2a)" +type Query { + dog: Dog +} + +enum DogCommand { SIT, DOWN, HEEL } + +type Dog implements Pet { + name: String! + nickname: String + barkVolume: Int + doesKnowCommand(dogCommand: DogCommand!): Boolean! + isHousetrained(atOtherHomes: Boolean): Boolean! + owner: Human +} + +interface Sentient { + name: String! +} + +interface Pet { + name: String! +} + +type Alien implements Sentient { + name: String! + homePlanet: String +} + +type Human implements Sentient { + name: String! + pets: [Pet!]! +} + +enum CatCommand { JUMP } + +type Cat implements Pet { + name: String! + nickname: String + doesKnowCommand(catCommand: CatCommand!): Boolean! + meowVolume: Int +} + +union CatOrDog = Cat | Dog +union DogOrHuman = Dog | Human +union HumanOrAlien = Human | Alien + +"Support for [Counter Example 105](https://spec.graphql.org/October2021/#example-77c2e)" +type Mutation { + mutateDog: MutateDogResult +} + +"Support for [Counter Example 105](https://spec.graphql.org/October2021/#example-77c2e)" +type MutateDogResult { + id: ID! +} + +"Support for [Example 108](https://spec.graphql.org/October2021/#example-5bbc3) - [Counter Example 112](https://spec.graphql.org/October2021/#example-a8fa1)" +type Subscription { + "Support for [Example 108](https://spec.graphql.org/October2021/#example-5bbc3) - [Counter Example 112](https://spec.graphql.org/October2021/#example-a8fa1)" + newMessage: Message! + "Support for [Counter Example 110](https://spec.graphql.org/October2021/#example-3997d) - [Counter Example 111](https://spec.graphql.org/October2021/#example-18466)" + disallowedSecondRootField: Boolean! +} + +"Support for [Example 108](https://spec.graphql.org/October2021/#example-5bbc3) - [Counter Example 112](https://spec.graphql.org/October2021/#example-a8fa1)" +type Message { + body: String + sender: ID! +} + +# https://spec.graphql.org/October2021/#example-9bada +extend type Query { + "Support for [Counter Example 127](https://spec.graphql.org/October2021/#example-77c2e)" + human: Human + "Support for [Counter Example 127](https://spec.graphql.org/October2021/#example-77c2e)" + pet: Pet + "Support for [Counter Example 127](https://spec.graphql.org/October2021/#example-77c2e)" + catOrDog: CatOrDog +} + +"Support for [Example 131](https://spec.graphql.org/October2021/#example-73706)" +type Arguments { + "Support for [Example 132](https://spec.graphql.org/October2021/#example-bda7e)" + multipleReqs(x: Int!, y: Int!): Int! + booleanArgField(booleanArg: Boolean): Boolean + floatArgField(floatArg: Float): Float + intArgField(intArg: Int): Int + nonNullBooleanArgField(nonNullBooleanArg: Boolean!): Boolean! + nonNullBooleanListField(nonNullBooleanListArg: [Boolean!]): [Boolean!] + booleanListArgField(booleanListArg: [Boolean]!): [Boolean] + optionalNonNullBooleanArgField(optionalBooleanArg: Boolean! = false): Boolean! +} + +# https://spec.graphql.org/October2021/#example-73706 +extend type Query { + "Support for [Example 131](https://spec.graphql.org/October2021/#example-73706)" + arguments: Arguments +} + +# https://spec.graphql.org/October2021/#example-bc12a +extend type Query { + "Support for [Example 156](https://spec.graphql.org/October2021/#example-bc12a)" + resource: Resource +} + +"Support for [Example 156](https://spec.graphql.org/October2021/#example-bc12a)" +interface Node { + id: ID! +} + +"Support for [Example 156](https://spec.graphql.org/October2021/#example-bc12a)" +interface Resource implements Node { + id: ID! + url: String +} + +"[Example 167](https://spec.graphql.org/October2021/#example-ce150)" +input ComplexInput { + name: String + owner: String +} + +extend type Query { + "[Example 167](https://spec.graphql.org/October2021/#example-ce150)" + findDog(complex: ComplexInput): Dog + "[Example 167](https://spec.graphql.org/October2021/#example-ce150)" + booleanList(booleanListArg: [Boolean!]): Boolean +} diff --git a/samples/validation/schema/validation_schema_files b/samples/validation/schema/validation_schema_files new file mode 100644 index 00000000..60750fdd --- /dev/null +++ b/samples/validation/schema/validation_schema_files @@ -0,0 +1,18 @@ +ValidationSchema.cpp +SentientObject.cpp +PetObject.cpp +NodeObject.cpp +ResourceObject.cpp +CatOrDogObject.cpp +DogOrHumanObject.cpp +HumanOrAlienObject.cpp +QueryObject.cpp +DogObject.cpp +AlienObject.cpp +HumanObject.cpp +CatObject.cpp +MutationObject.cpp +MutateDogResultObject.cpp +SubscriptionObject.cpp +MessageObject.cpp +ArgumentsObject.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1160763d..3a798528 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -cmake_minimum_required(VERSION 3.8.2) +cmake_minimum_required(VERSION 3.15) if(GRAPHQL_UPDATE_VERSION) # internal/Version.h @@ -61,10 +61,57 @@ function(add_bigobj_flag target) endif() endfunction() +add_library(graphqlcoro INTERFACE) +target_compile_features(graphqlcoro INTERFACE cxx_std_20) + +function(check_coroutine_impl COROUTINE_HEADER COROUTINE_NAMESPACE OPTIONAL_FLAGS OUT_RESULT) + set(TEST_FILE "test_${OUT_RESULT}.cpp") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/test_coroutine.cpp.in ${TEST_FILE} @ONLY) + + try_compile(TEST_RESULT + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/${TEST_FILE} + CXX_STANDARD 20) + + if(NOT TEST_RESULT) + # Retry with each of the optional flags. + foreach(OPTIONAL_FLAG IN LISTS OPTIONAL_FLAGS) + try_compile(TEST_RESULT + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/${TEST_FILE} + CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPTIONAL_FLAG}" + CXX_STANDARD 20) + + if(TEST_RESULT) + # Looks like the optional flag was required, go ahead and add it to the compile options. + target_compile_options(graphqlcoro INTERFACE ${OPTIONAL_FLAG}) + break() + endif() + endforeach(OPTIONAL_FLAG) + endif() + + set(${OUT_RESULT} ${TEST_RESULT} PARENT_SCOPE) +endfunction() + +check_coroutine_impl("coroutine" "std" "-fcoroutines" STD_COROUTINE) +if(STD_COROUTINE) + message(STATUS "Using std coroutine") +else() + check_coroutine_impl("experimental/coroutine" "std::experimental" "" STD_EXPERIMENTAL_COROUTINE) + if(STD_EXPERIMENTAL_COROUTINE) + message(STATUS "Using std::experimental coroutine") + target_compile_definitions(graphqlcoro INTERFACE USE_STD_EXPERIMENTAL_COROUTINE) + else() + message(FATAL_ERROR "Missing coroutine support") + endif() +endif() + # graphqlpeg add_library(graphqlpeg SyntaxTree.cpp) add_library(cppgraphqlgen::graphqlpeg ALIAS graphqlpeg) -target_link_libraries(graphqlpeg PUBLIC taocpp::pegtl) +target_link_libraries(graphqlpeg PUBLIC + graphqlcoro + taocpp::pegtl) target_include_directories(graphqlpeg PUBLIC $ $ @@ -91,6 +138,7 @@ add_library(cppgraphqlgen::graphqlresponse ALIAS graphqlresponse) target_include_directories(graphqlresponse PUBLIC $ $) +target_link_libraries(graphqlresponse PUBLIC graphqlcoro) if(GRAPHQL_UPDATE_VERSION) update_version_rc(graphqlresponse) @@ -104,7 +152,6 @@ if(WIN32 AND BUILD_SHARED_LIBS) add_version_rc(graphqlresponse) endif() - # Common schemagen and clientgen dependencies if(GRAPHQL_BUILD_SCHEMAGEN OR GRAPHQL_BUILD_CLIENTGEN) add_library(generator_util STATIC @@ -198,18 +245,12 @@ endif() # Common schemagen and clientgen filesystem and Boost dependencies if(GRAPHQL_BUILD_SCHEMAGEN OR GRAPHQL_BUILD_CLIENTGEN) - set(BOOST_COMPONENTS program_options) - set(BOOST_LIBRARIES Boost::program_options) - # Try compiling a test program with std::filesystem or one of its alternatives. - function(check_filesystem_impl FILESYSTEM_HEADER FILESYSTEM_NAMESPACE OPTIONAL_LIBS OUT_RESULT) - set(TEST_FILE "test_${OUT_RESULT}.cpp") - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/test_filesystem.cpp.in ${TEST_FILE} @ONLY) - + function(check_filesystem_impl OPTIONAL_LIBS) try_compile(TEST_RESULT ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_BINARY_DIR}/${TEST_FILE} - CXX_STANDARD 17) + ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/test_filesystem.cpp + CXX_STANDARD 20) if(NOT TEST_RESULT) # Retry with each of the optional libraries. @@ -218,7 +259,7 @@ if(GRAPHQL_BUILD_SCHEMAGEN OR GRAPHQL_BUILD_CLIENTGEN) ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${TEST_FILE} LINK_LIBRARIES ${OPTIONAL_LIB} - CXX_STANDARD 17) + CXX_STANDARD 20) if(TEST_RESULT) # Looks like the optional library was required, go ahead and add it to the link options. @@ -232,66 +273,24 @@ if(GRAPHQL_BUILD_SCHEMAGEN OR GRAPHQL_BUILD_CLIENTGEN) endif() endforeach(OPTIONAL_LIB) endif() - - set(${OUT_RESULT} ${TEST_RESULT} PARENT_SCOPE) endfunction(check_filesystem_impl) - # Try compiling a minimal program with each header/namespace, in order of preference: - # C++17: #include // std::filesystem - # Experimental C++17: #include // std::experimental::filesystem - # Boost.Filesystem: #include // boost::filesystem - check_filesystem_impl("filesystem" "std::filesystem" "stdc++fs;c++fs" STD_FILESYTEM) - if(STD_FILESYTEM) - if(GRAPHQL_BUILD_SCHEMAGEN) - target_compile_definitions(schemagen PRIVATE USE_STD_FILESYSTEM) - endif() - if(GRAPHQL_BUILD_CLIENTGEN) - target_compile_definitions(clientgen PRIVATE USE_STD_FILESYSTEM) - endif() - else() - check_filesystem_impl("experimental/filesystem" "std::experimental::filesystem" "stdc++fs;c++fs" STD_EXPERIMENTAL_FILESYTEM) - if(STD_EXPERIMENTAL_FILESYTEM) - if(GRAPHQL_BUILD_SCHEMAGEN) - target_compile_definitions(schemagen PRIVATE USE_STD_EXPERIMENTAL_FILESYSTEM) - endif() - if(GRAPHQL_BUILD_CLIENTGEN) - target_compile_definitions(clientgen PRIVATE USE_STD_EXPERIMENTAL_FILESYSTEM) - endif() - else() - set(BOOST_COMPONENTS ${BOOST_COMPONENTS} filesystem) - set(BOOST_LIBRARIES ${BOOST_LIBRARIES} Boost::filesystem) - if(GRAPHQL_BUILD_SCHEMAGEN) - target_compile_definitions(schemagen PRIVATE USE_BOOST_FILESYSTEM) - endif() - if(GRAPHQL_BUILD_CLIENTGEN) - target_compile_definitions(clientgen PRIVATE USE_BOOST_FILESYSTEM) - endif() - endif() - endif() + # Try compiling a minimal program without any extra libraries, then with each optional library until it succeeded: + # stdc++fs + # c++fs + check_filesystem_impl("stdc++fs;c++fs" STD_FILESYTEM) - find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) + find_package(Boost REQUIRED COMPONENTS program_options) if(GRAPHQL_BUILD_SCHEMAGEN) - target_link_libraries(schemagen PRIVATE ${BOOST_LIBRARIES}) + target_link_libraries(schemagen PRIVATE Boost::program_options) endif() if(GRAPHQL_BUILD_CLIENTGEN) - target_link_libraries(clientgen PRIVATE ${BOOST_LIBRARIES}) + target_link_libraries(clientgen PRIVATE Boost::program_options) endif() endif() # introspection -if(GRAPHQL_UPDATE_SAMPLES) - add_custom_command( - OUTPUT updated_introspection - COMMAND schemagen --introspection - COMMAND ${CMAKE_COMMAND} -E copy_if_different IntrospectionSchema.cpp ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND ${CMAKE_COMMAND} -E copy_if_different IntrospectionSchema.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/introspection - COMMAND ${CMAKE_COMMAND} -E touch updated_introspection - DEPENDS schemagen - COMMENT "Updating IntrospectionSchema files") - - add_custom_target(update_introspection ALL - DEPENDS updated_introspection) -endif() +add_subdirectory(introspection) # graphqlservice add_library(graphqlservice @@ -300,14 +299,14 @@ add_library(graphqlservice Validation.cpp) add_library(cppgraphqlgen::graphqlservice ALIAS graphqlservice) target_link_libraries(graphqlservice PUBLIC - graphqlpeg - graphqlresponse - Threads::Threads) + graphqlpeg + graphqlresponse + Threads::Threads) if(GRAPHQL_UPDATE_SAMPLES) # Even though this target doesn't build IntrospectionSchema.cpp, it still # depends on IntrospectionSchema.h for some enum definitions. - add_dependencies(graphqlservice update_introspection) + add_dependencies(graphqlservice copy_introspection_schema_headers) endif() if(GRAPHQL_UPDATE_VERSION) @@ -323,9 +322,8 @@ if(WIN32 AND BUILD_SHARED_LIBS) endif() # graphqlintrospection -add_library(graphqlintrospection - Introspection.cpp - IntrospectionSchema.cpp) +file(GLOB INTROSPECTION_SCHEMA_FILES ${CMAKE_CURRENT_SOURCE_DIR}/introspection/*.cpp) +add_library(graphqlintrospection Introspection.cpp ${INTROSPECTION_SCHEMA_FILES}) add_library(cppgraphqlgen::graphqlintrospection ALIAS graphqlintrospection) target_link_libraries(graphqlintrospection PUBLIC graphqlservice) @@ -349,8 +347,8 @@ endif() add_library(graphqlclient GraphQLClient.cpp) add_library(cppgraphqlgen::graphqlclient ALIAS graphqlclient) target_link_libraries(graphqlclient PUBLIC - graphqlpeg - graphqlresponse) + graphqlpeg + graphqlresponse) if(GRAPHQL_UPDATE_VERSION) update_version_rc(graphqlclient) @@ -398,6 +396,7 @@ install(TARGETS graphqlclient graphqlintrospection graphqlpeg + graphqlcoro graphqlresponse graphqlservice EXPORT cppgraphqlgen-targets @@ -414,8 +413,10 @@ install(FILES DESTINATION ${GRAPHQL_INSTALL_INCLUDE_DIR}/graphqlservice) install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/internal/Awaitable.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/internal/Base64.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/internal/Grammar.h + ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/internal/Introspection.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/internal/Schema.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/internal/SortedMap.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/internal/SyntaxTree.h @@ -423,12 +424,6 @@ install(FILES CONFIGURATIONS ${GRAPHQL_INSTALL_CONFIGURATIONS} DESTINATION ${GRAPHQL_INSTALL_INCLUDE_DIR}/graphqlservice/internal) -install(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/introspection/Introspection.h - ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/introspection/IntrospectionSchema.h - CONFIGURATIONS ${GRAPHQL_INSTALL_CONFIGURATIONS} - DESTINATION ${GRAPHQL_INSTALL_INCLUDE_DIR}/graphqlservice/introspection) - # graphqljson if(BUILD_GRAPHQLJSON) option(GRAPHQL_BUILD_TESTS "Build the tests and sample schema library." ON) diff --git a/src/ClientGenerator.cpp b/src/ClientGenerator.cpp index 5c699732..14b7d9a6 100644 --- a/src/ClientGenerator.cpp +++ b/src/ClientGenerator.cpp @@ -20,26 +20,8 @@ #pragma warning(pop) #endif // _MSC_VER -// clang-format off -#ifdef USE_STD_FILESYSTEM - #include - namespace fs = std::filesystem; -#else - #ifdef USE_STD_EXPERIMENTAL_FILESYSTEM - #include - namespace fs = std::experimental::filesystem; - #else - #ifdef USE_BOOST_FILESYSTEM - #include - namespace fs = boost::filesystem; - #else - #error "No std::filesystem implementation defined" - #endif - #endif -#endif -// clang-format on - #include +#include #include #include #include @@ -52,7 +34,7 @@ namespace graphql::generator::client { Generator::Generator( SchemaOptions&& schemaOptions, RequestOptions&& requestOptions, GeneratorOptions&& options) - : _schemaLoader(std::make_optional(std::move(schemaOptions))) + : _schemaLoader(std::move(schemaOptions)) , _requestLoader(std::move(requestOptions), _schemaLoader) , _options(std::move(options)) , _headerDir(getHeaderDir()) @@ -64,9 +46,9 @@ Generator::Generator( std::string Generator::getHeaderDir() const noexcept { - if (_options.paths) + if (!_options.paths.headerPath.empty()) { - return fs::path { _options.paths->headerPath }.string(); + return std::filesystem::path { _options.paths.headerPath }.string(); } else { @@ -76,9 +58,9 @@ std::string Generator::getHeaderDir() const noexcept std::string Generator::getSourceDir() const noexcept { - if (_options.paths) + if (!_options.paths.sourcePath.empty()) { - return fs::path(_options.paths->sourcePath).string(); + return std::filesystem::path(_options.paths.sourcePath).string(); } else { @@ -88,7 +70,7 @@ std::string Generator::getSourceDir() const noexcept std::string Generator::getHeaderPath() const noexcept { - fs::path fullPath { _headerDir }; + std::filesystem::path fullPath { _headerDir }; fullPath /= (std::string { _schemaLoader.getFilenamePrefix() } + "Client.h"); @@ -97,7 +79,7 @@ std::string Generator::getHeaderPath() const noexcept std::string Generator::getSourcePath() const noexcept { - fs::path fullPath { _sourceDir }; + std::filesystem::path fullPath { _sourceDir }; fullPath /= (std::string { _schemaLoader.getFilenamePrefix() } + "Client.cpp"); @@ -188,7 +170,8 @@ std::vector Generator::Build() const noexcept bool Generator::outputHeader() const noexcept { std::ofstream headerFile(_headerPath, std::ios_base::trunc); - IncludeGuardScope includeGuard { headerFile, fs::path(_headerPath).filename().string() }; + IncludeGuardScope includeGuard { headerFile, + std::filesystem::path(_headerPath).filename().string() }; headerFile << R"cpp(#include "graphqlservice/GraphQLClient.h" #include "graphqlservice/GraphQLParse.h" @@ -223,7 +206,8 @@ static_assert(graphql::internal::MinorVersion == )cpp" { pendingSeparator.reset(); - headerFile << R"cpp(enum class )cpp" << _schemaLoader.getCppType(enumType->name()) << R"cpp( + headerFile << R"cpp(enum class )cpp" << _schemaLoader.getCppType(enumType->name()) + << R"cpp( { )cpp"; for (const auto& enumValue : enumType->enumValues()) @@ -324,7 +308,7 @@ response::Value serializeVariables(Variables&& variables); headerFile << R"cpp(}; -Response parseResponse(response::Value&& response); +Response parseResponse(response::Value response); )cpp"; pendingSeparator.add(); @@ -451,8 +435,8 @@ bool Generator::outputSource() const noexcept #include #include -#include #include +#include #include using namespace std::literals; @@ -512,7 +496,7 @@ response::Value ModifiedVariable<)cpp" { response::Value result { response::Type::EnumValue }; - result.set(response::StringType { s_names)cpp" + result.set(std::string { s_names)cpp" << cppType << R"cpp([static_cast(value)] }); return result; @@ -567,7 +551,7 @@ response::Value ModifiedVariable )cpp" << cppType << R"cpp( ModifiedResponse<)cpp" - << cppType << R"cpp(>::parse(response::Value&& value) + << cppType << R"cpp(>::parse(response::Value value) { if (!value.maybe_enum()) { @@ -577,7 +561,7 @@ response::Value ModifiedVariable()); + << R"cpp(.cend(), value.release()); if (itr == s_names)cpp" << cppType << R"cpp(.cend()) @@ -639,7 +623,7 @@ response::Value serializeVariables(Variables&& variables) } sourceFile << R"cpp( -Response parseResponse(response::Value&& response) +Response parseResponse(response::Value response) { Response result; @@ -757,7 +741,7 @@ bool Generator::outputModifiedResponseImplementation(std::ostream& sourceFile, template <> )cpp" << cppType << R"cpp( ModifiedResponse<)cpp" << cppType - << R"cpp(>::parse(response::Value&& response) + << R"cpp(>::parse(response::Value response) { )cpp" << cppType << R"cpp( result; @@ -971,8 +955,7 @@ int main(int argc, char** argv) noIntrospection, }, graphql::generator::client::GeneratorOptions { - graphql::generator::client::GeneratorPaths { std::move(headerDir), - std::move(sourceDir) }, + { std::move(headerDir), std::move(sourceDir) }, verbose, }) .Build(); diff --git a/src/GeneratorLoader.cpp b/src/GeneratorLoader.cpp index 6e1edd6e..c57ed8fe 100644 --- a/src/GeneratorLoader.cpp +++ b/src/GeneratorLoader.cpp @@ -134,7 +134,7 @@ void DefaultValueVisitor::visitNullValue(const peg::ast_node& /*nullValue*/) void DefaultValueVisitor::visitEnumValue(const peg::ast_node& enumValue) { _value = response::Value(response::Type::EnumValue); - _value.set(enumValue.string()); + _value.set(enumValue.string()); } void DefaultValueVisitor::visitListValue(const peg::ast_node& listValue) diff --git a/src/GraphQLClient.cpp b/src/GraphQLClient.cpp index bb9b45f5..b005c32b 100644 --- a/src/GraphQLClient.cpp +++ b/src/GraphQLClient.cpp @@ -21,7 +21,7 @@ ErrorLocation parseServiceErrorLocation(response::Value&& location) { if (member.second.type() == response::Type::Int) { - result.line = static_cast(member.second.get()); + result.line = static_cast(member.second.get()); } continue; @@ -31,7 +31,7 @@ ErrorLocation parseServiceErrorLocation(response::Value&& location) { if (member.second.type() == response::Type::Int) { - result.column = static_cast(member.second.get()); + result.column = static_cast(member.second.get()); } continue; @@ -44,16 +44,16 @@ ErrorLocation parseServiceErrorLocation(response::Value&& location) ErrorPathSegment parseServiceErrorPathSegment(response::Value&& segment) { - ErrorPathSegment result { response::IntType {} }; + ErrorPathSegment result { int {} }; switch (segment.type()) { case response::Type::Int: - result = segment.get(); + result = segment.get(); break; case response::Type::String: - result = segment.release(); + result = segment.release(); break; default: @@ -77,7 +77,7 @@ Error parseServiceError(response::Value&& error) { if (member.second.type() == response::Type::String) { - result.message = member.second.release(); + result.message = member.second.release(); } continue; @@ -93,10 +93,9 @@ Error parseServiceError(response::Value&& error) std::transform(locations.begin(), locations.end(), std::back_inserter(result.locations), - [](response::Value& location) - { - return parseServiceErrorLocation(std::move(location)); - }); + [](response::Value& location) { + return parseServiceErrorLocation(std::move(location)); + }); } continue; @@ -112,10 +111,9 @@ Error parseServiceError(response::Value&& error) std::transform(segments.begin(), segments.end(), std::back_inserter(result.path), - [](response::Value& segment) - { - return parseServiceErrorPathSegment(std::move(segment)); - }); + [](response::Value& segment) { + return parseServiceErrorPathSegment(std::move(segment)); + }); } continue; @@ -126,7 +124,7 @@ Error parseServiceError(response::Value&& error) return result; } -ServiceResponse parseServiceResponse(response::Value&& response) +ServiceResponse parseServiceResponse(response::Value response) { ServiceResponse result; @@ -167,25 +165,25 @@ ServiceResponse parseServiceResponse(response::Value&& response) } template <> -response::Value ModifiedVariable::serialize(response::IntType&& value) +response::Value ModifiedVariable::serialize(int&& value) { return response::Value { value }; } template <> -response::Value ModifiedVariable::serialize(response::FloatType&& value) +response::Value ModifiedVariable::serialize(double&& value) { return response::Value { value }; } template <> -response::Value ModifiedVariable::serialize(response::StringType&& value) +response::Value ModifiedVariable::serialize(std::string&& value) { return response::Value { std::move(value) }; } template <> -response::Value ModifiedVariable::serialize(response::BooleanType&& value) +response::Value ModifiedVariable::serialize(bool&& value) { return response::Value { value }; } @@ -203,57 +201,57 @@ response::Value ModifiedVariable::serialize(response::IdType&& } template <> -response::IntType ModifiedResponse::parse(response::Value&& value) +int ModifiedResponse::parse(response::Value value) { if (value.type() != response::Type::Int) { throw std::logic_error { "not an integer" }; } - return value.get(); + return value.get(); } template <> -response::FloatType ModifiedResponse::parse(response::Value&& value) +double ModifiedResponse::parse(response::Value value) { if (value.type() != response::Type::Float && value.type() != response::Type::Int) { throw std::logic_error { "not a float" }; } - return value.get(); + return value.get(); } template <> -response::StringType ModifiedResponse::parse(response::Value&& value) +std::string ModifiedResponse::parse(response::Value value) { if (value.type() != response::Type::String) { throw std::logic_error { "not a string" }; } - return value.release(); + return value.release(); } template <> -response::BooleanType ModifiedResponse::parse(response::Value&& value) +bool ModifiedResponse::parse(response::Value value) { if (value.type() != response::Type::Boolean) { throw std::logic_error { "not a boolean" }; } - return value.get(); + return value.get(); } template <> -response::Value ModifiedResponse::parse(response::Value&& value) +response::Value ModifiedResponse::parse(response::Value value) { - return response::Value { std::move(value) }; + return value; } template <> -response::IdType ModifiedResponse::parse(response::Value&& value) +response::IdType ModifiedResponse::parse(response::Value value) { if (value.type() != response::Type::String) { diff --git a/src/GraphQLResponse.cpp b/src/GraphQLResponse.cpp index 7ddaf651..e773d8c9 100644 --- a/src/GraphQLResponse.cpp +++ b/src/GraphQLResponse.cpp @@ -42,6 +42,11 @@ bool Value::ScalarData::operator==(const ScalarData& rhs) const template <> void Value::set(StringType&& value) { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (std::holds_alternative(_data)) { std::get(_data) = std::move(value); @@ -59,6 +64,11 @@ void Value::set(StringType&& value) template <> void Value::set(BooleanType value) { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::set for BooleanType"); @@ -70,6 +80,11 @@ void Value::set(BooleanType value) template <> void Value::set(IntType value) { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (std::holds_alternative(_data)) { // Coerce IntType to FloatType @@ -88,6 +103,11 @@ void Value::set(IntType value) template <> void Value::set(FloatType value) { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::set for FloatType"); @@ -99,6 +119,11 @@ void Value::set(FloatType value) template <> void Value::set(ScalarType&& value) { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::set for ScalarType"); @@ -110,6 +135,11 @@ void Value::set(ScalarType&& value) template <> void Value::set(const IdType& value) { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::set for IdType"); @@ -121,35 +151,41 @@ void Value::set(const IdType& value) template <> const MapType& Value::get() const { - if (!std::holds_alternative(_data)) + const auto& typeData = data(); + + if (!std::holds_alternative(typeData)) { throw std::logic_error("Invalid call to Value::get for MapType"); } - return std::get(_data).map; + return std::get(typeData).map; } template <> const ListType& Value::get() const { - if (!std::holds_alternative(_data)) + const auto& typeData = data(); + + if (!std::holds_alternative(typeData)) { throw std::logic_error("Invalid call to Value::get for ListType"); } - return std::get(_data); + return std::get(typeData); } template <> const StringType& Value::get() const { - if (std::holds_alternative(_data)) + const auto& typeData = data(); + + if (std::holds_alternative(typeData)) { - return std::get(_data); + return std::get(typeData); } - else if (std::holds_alternative(_data)) + else if (std::holds_alternative(typeData)) { - return std::get(_data).string; + return std::get(typeData).string; } throw std::logic_error("Invalid call to Value::get for StringType"); @@ -158,51 +194,59 @@ const StringType& Value::get() const template <> BooleanType Value::get() const { - if (!std::holds_alternative(_data)) + const auto& typeData = data(); + + if (!std::holds_alternative(typeData)) { throw std::logic_error("Invalid call to Value::get for BooleanType"); } - return std::get(_data); + return std::get(typeData); } template <> IntType Value::get() const { - if (!std::holds_alternative(_data)) + const auto& typeData = data(); + + if (!std::holds_alternative(typeData)) { throw std::logic_error("Invalid call to Value::get for IntType"); } - return std::get(_data); + return std::get(typeData); } template <> FloatType Value::get() const { - if (std::holds_alternative(_data)) + const auto& typeData = data(); + + if (std::holds_alternative(typeData)) { // Coerce IntType to FloatType - return static_cast(std::get(_data)); + return static_cast(std::get(typeData)); } - if (!std::holds_alternative(_data)) + if (!std::holds_alternative(typeData)) { throw std::logic_error("Invalid call to Value::get for FloatType"); } - return std::get(_data); + return std::get(typeData); } template <> const ScalarType& Value::get() const { - if (!std::holds_alternative(_data)) + const auto& typeData = data(); + + if (!std::holds_alternative(typeData)) { throw std::logic_error("Invalid call to Value::get for ScalarType"); } - const auto& scalar = std::get(_data).scalar; + const auto& scalar = std::get(typeData).scalar; if (!scalar) { @@ -215,17 +259,24 @@ const ScalarType& Value::get() const template <> IdType Value::get() const { - if (!std::holds_alternative(_data)) + const auto& typeData = data(); + + if (!std::holds_alternative(typeData)) { throw std::logic_error("Invalid call to Value::get for IdType"); } - return internal::Base64::fromBase64(std::get(_data).string); + return internal::Base64::fromBase64(std::get(typeData).string); } template <> MapType Value::release() { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::release for MapType"); @@ -242,6 +293,11 @@ MapType Value::release() template <> ListType Value::release() { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::release for ListType"); @@ -255,6 +311,11 @@ ListType Value::release() template <> StringType Value::release() { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + StringType result; if (std::holds_alternative(_data)) @@ -279,6 +340,11 @@ StringType Value::release() template <> ScalarType Value::release() { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::release for ScalarType"); @@ -299,6 +365,11 @@ ScalarType Value::release() template <> IdType Value::release() { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::release for IdType"); @@ -396,6 +467,12 @@ Value::Value(Value&& other) noexcept Value::Value(const Value& other) { + if (std::holds_alternative(other._data)) + { + _data = std::get(other._data); + return; + } + switch (other.type()) { case Type::Map: @@ -471,6 +548,16 @@ Value::Value(const Value& other) } } +Value::Value(std::shared_ptr value) noexcept + : _data(TypeData { value }) +{ +} + +const Value::TypeData& Value::data() const noexcept +{ + return std::holds_alternative(_data) ? std::get(_data)->data() : _data; +} + Value& Value::operator=(Value&& rhs) noexcept { if (&rhs != this) @@ -483,7 +570,7 @@ Value& Value::operator=(Value&& rhs) noexcept bool Value::operator==(const Value& rhs) const noexcept { - return _data == rhs._data; + return data() == rhs.data(); } bool Value::operator!=(const Value& rhs) const noexcept @@ -493,6 +580,11 @@ bool Value::operator!=(const Value& rhs) const noexcept Type Value::type() const noexcept { + if (std::holds_alternative(_data)) + { + return std::get(_data)->type(); + } + // As long as the order of the variant alternatives matches the Type enum, we can cast the index // to the Type in one step. static_assert( @@ -533,7 +625,11 @@ Type Value::type() const noexcept Value&& Value::from_json() noexcept { - if (std::holds_alternative(_data)) + if (std::holds_alternative(_data)) + { + _data = StringData { { get() }, true }; + } + else if (std::holds_alternative(_data)) { std::get(_data).from_json = true; } @@ -543,12 +639,20 @@ Value&& Value::from_json() noexcept bool Value::maybe_enum() const noexcept { - return std::holds_alternative(_data) - || (std::holds_alternative(_data) && std::get(_data).from_json); + const auto& typeData = data(); + + return std::holds_alternative(typeData) + || (std::holds_alternative(typeData) + && std::get(typeData).from_json); } void Value::reserve(size_t count) { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + switch (type()) { case Type::Map: @@ -577,12 +681,12 @@ size_t Value::size() const { case Type::Map: { - return std::get(_data).map.size(); + return std::get(data()).map.size(); } case Type::List: { - return std::get(_data).size(); + return std::get(data()).size(); } default: @@ -592,6 +696,11 @@ size_t Value::size() const bool Value::emplace_back(std::string&& name, Value&& value) { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::emplace_back for MapType"); @@ -620,12 +729,14 @@ bool Value::emplace_back(std::string&& name, Value&& value) MapType::const_iterator Value::find(std::string_view name) const { - if (!std::holds_alternative(_data)) + const auto& typeData = data(); + + if (!std::holds_alternative(typeData)) { throw std::logic_error("Invalid call to Value::find for MapType"); } - const auto& mapData = std::get(_data); + const auto& mapData = std::get(typeData); const auto [itr, itrEnd] = std::equal_range(mapData.members.cbegin(), mapData.members.cend(), std::nullopt, @@ -645,22 +756,26 @@ MapType::const_iterator Value::find(std::string_view name) const MapType::const_iterator Value::begin() const { - if (!std::holds_alternative(_data)) + const auto& typeData = data(); + + if (!std::holds_alternative(typeData)) { throw std::logic_error("Invalid call to Value::begin for MapType"); } - return std::get(_data).map.cbegin(); + return std::get(typeData).map.cbegin(); } MapType::const_iterator Value::end() const { - if (!std::holds_alternative(_data)) + const auto& typeData = data(); + + if (!std::holds_alternative(typeData)) { throw std::logic_error("Invalid call to Value::end for MapType"); } - return std::get(_data).map.cend(); + return std::get(typeData).map.cend(); } const Value& Value::operator[](std::string_view name) const @@ -677,6 +792,11 @@ const Value& Value::operator[](std::string_view name) const void Value::emplace_back(Value&& value) { + if (std::holds_alternative(_data)) + { + *this = Value { *std::get(_data) }; + } + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::emplace_back for ListType"); @@ -687,12 +807,96 @@ void Value::emplace_back(Value&& value) const Value& Value::operator[](size_t index) const { - if (!std::holds_alternative(_data)) + const auto& typeData = data(); + + if (!std::holds_alternative(typeData)) { throw std::logic_error("Invalid call to Value::operator[] for ListType"); } - return std::get(_data).at(index); + return std::get(typeData).at(index); +} + +void Writer::write(Value response) const +{ + switch (response.type()) + { + case Type::Map: + { + auto members = response.release(); + + _concept->start_object(); + + for (auto& entry : members) + { + _concept->add_member(entry.first); + write(std::move(entry.second)); + } + + _concept->end_object(); + break; + } + + case Type::List: + { + auto elements = response.release(); + + _concept->start_array(); + + for (auto& entry : elements) + { + write(std::move(entry)); + } + + _concept->end_arrary(); + break; + } + + case Type::String: + case Type::EnumValue: + { + auto value = response.release(); + + _concept->write_string(value); + break; + } + + case Type::Null: + { + _concept->write_null(); + break; + } + + case Type::Boolean: + { + _concept->write_bool(response.get()); + break; + } + + case Type::Int: + { + _concept->write_int(response.get()); + break; + } + + case Type::Float: + { + _concept->write_float(response.get()); + break; + } + + case Type::Scalar: + { + write(response.release()); + break; + } + + default: + { + _concept->write_null(); + break; + } + } } } // namespace graphql::response diff --git a/src/GraphQLService.cpp b/src/GraphQLService.cpp index e1c409a6..4d0b77ef 100644 --- a/src/GraphQLService.cpp +++ b/src/GraphQLService.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace graphql::service { @@ -29,9 +30,9 @@ void addErrorLocation(const schema_location& location, response::Value& error) errorLocation.reserve(2); errorLocation.emplace_back(std::string { strLine }, - response::Value(static_cast(location.line))); + response::Value(static_cast(location.line))); errorLocation.emplace_back(std::string { strColumn }, - response::Value(static_cast(location.column))); + response::Value(static_cast(location.column))); response::Value errorLocations(response::Type::List); @@ -60,8 +61,7 @@ void addErrorPath(const error_path& path, response::Value& error) } else if (std::holds_alternative(segment)) { - errorPath.emplace_back( - response::Value(static_cast(std::get(segment)))); + errorPath.emplace_back(response::Value(static_cast(std::get(segment)))); } } @@ -164,18 +164,12 @@ response::Value schema_exception::getErrors() return buildErrorValues(std::move(_structuredErrors)); } -FieldParams::FieldParams(SelectionSetParams&& selectionSetParams, response::Value&& directives) +FieldParams::FieldParams(SelectionSetParams&& selectionSetParams, Directives directives) : SelectionSetParams(std::move(selectionSetParams)) , fieldDirectives(std::move(directives)) { } -FieldParams::FieldParams(const SelectionSetParams& selectionSetParams, response::Value&& directives) - : SelectionSetParams(selectionSetParams) - , fieldDirectives(std::move(directives)) -{ -} - // ValueVisitor visits the AST and builds a response::Value representation of any value // hardcoded or referencing a variable in an operation. class ValueVisitor @@ -302,7 +296,7 @@ void ValueVisitor::visitNullValue(const peg::ast_node& /*nullValue*/) void ValueVisitor::visitEnumValue(const peg::ast_node& enumValue) { _value = response::Value(response::Type::EnumValue); - _value.set(enumValue.string()); + _value.set(enumValue.string()); } void ValueVisitor::visitListValue(const peg::ast_node& listValue) @@ -343,27 +337,26 @@ class DirectiveVisitor void visit(const peg::ast_node& directives); bool shouldSkip() const; - response::Value getDirectives(); + Directives getDirectives(); private: const response::Value& _variables; - response::Value _directives; + Directives _directives; }; DirectiveVisitor::DirectiveVisitor(const response::Value& variables) : _variables(variables) - , _directives(response::Type::Map) { } void DirectiveVisitor::visit(const peg::ast_node& directives) { - response::Value result(response::Type::Map); + Directives result; for (const auto& directive : directives.children) { - std::string directiveName; + std::string_view directiveName; peg::on_first_child(*directive, [&directiveName](const peg::ast_node& child) { @@ -390,13 +383,13 @@ void DirectiveVisitor::visit(const peg::ast_node& directives) } }); - result.emplace_back(std::move(directiveName), std::move(directiveArguments)); + result.emplace_back(directiveName, std::move(directiveArguments)); } _directives = std::move(result); } -response::Value DirectiveVisitor::getDirectives() +Directives DirectiveVisitor::getDirectives() { auto result = std::move(_directives); @@ -405,15 +398,19 @@ response::Value DirectiveVisitor::getDirectives() bool DirectiveVisitor::shouldSkip() const { - static const std::array, 2> skippedNames = { - std::make_pair(true, "skip"), - std::make_pair(false, "include"), + constexpr std::array, 2> c_skippedDirectives = { + std::make_pair(true, R"gql(skip)gql"sv), + std::make_pair(false, R"gql(include)gql"sv), }; - for (const auto& entry : skippedNames) + for (const auto& entry : c_skippedDirectives) { const bool skip = entry.first; - auto itrDirective = _directives.find(entry.second); + auto itrDirective = std::find_if(_directives.cbegin(), + _directives.cend(), + [directiveName = entry.second](const auto& directive) noexcept { + return directive.first == directiveName; + }); if (itrDirective == _directives.end()) { @@ -447,7 +444,7 @@ bool DirectiveVisitor::shouldSkip() const throw schema_exception { { error.str() } }; } - argumentTrue = argument.second.get(); + argumentTrue = argument.second.get(); argumentFalse = !argumentTrue; } @@ -474,7 +471,6 @@ bool DirectiveVisitor::shouldSkip() const Fragment::Fragment(const peg::ast_node& fragmentDefinition, const response::Value& variables) : _type(fragmentDefinition.children[1]->children.front()->string_view()) - , _directives(response::Type::Map) , _selection(*(fragmentDefinition.children.back())) { peg::on_first_child(fragmentDefinition, @@ -496,14 +492,14 @@ const peg::ast_node& Fragment::getSelection() const return _selection.get(); } -const response::Value& Fragment::getDirectives() const +const Directives& Fragment::getDirectives() const { return _directives; } ResolverParams::ResolverParams(const SelectionSetParams& selectionSetParams, - const peg::ast_node& field, std::string&& fieldName, response::Value&& arguments, - response::Value&& fieldDirectives, const peg::ast_node* selection, const FragmentMap& fragments, + const peg::ast_node& field, std::string&& fieldName, response::Value arguments, + Directives fieldDirectives, const peg::ast_node* selection, const FragmentMap& fragments, const response::Value& variables) : SelectionSetParams(selectionSetParams) , field(field) @@ -524,47 +520,47 @@ schema_location ResolverParams::getLocation() const } template <> -response::IntType ModifiedArgument::convert(const response::Value& value) +int ModifiedArgument::convert(const response::Value& value) { if (value.type() != response::Type::Int) { throw schema_exception { { "not an integer" } }; } - return value.get(); + return value.get(); } template <> -response::FloatType ModifiedArgument::convert(const response::Value& value) +double ModifiedArgument::convert(const response::Value& value) { if (value.type() != response::Type::Float && value.type() != response::Type::Int) { throw schema_exception { { "not a float" } }; } - return value.get(); + return value.get(); } template <> -response::StringType ModifiedArgument::convert(const response::Value& value) +std::string ModifiedArgument::convert(const response::Value& value) { if (value.type() != response::Type::String) { throw schema_exception { { "not a string" } }; } - return value.get(); + return value.get(); } template <> -response::BooleanType ModifiedArgument::convert(const response::Value& value) +bool ModifiedArgument::convert(const response::Value& value) { if (value.type() != response::Type::Boolean) { throw schema_exception { { "not a boolean" } }; } - return value.get(); + return value.get(); } template <> @@ -597,7 +593,7 @@ response::IdType ModifiedArgument::convert(const response::Val void blockSubFields(const ResolverParams& params) { - // http://spec.graphql.org/June2018/#sec-Leaf-Field-Selections + // https://spec.graphql.org/October2021/#sec-Leaf-Field-Selections if (params.selection != nullptr) { auto position = params.selection->begin(); @@ -612,60 +608,52 @@ void blockSubFields(const ResolverParams& params) } template <> -std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params) +AwaitableResolver ModifiedResult::convert(AwaitableScalar result, ResolverParams params) { blockSubFields(params); - return resolve(std::move(result), - std::move(params), - [](response::IntType&& value, const ResolverParams&) { - return response::Value(value); - }); + return resolve(std::move(result), std::move(params), [](int&& value, const ResolverParams&) { + return response::Value(value); + }); } template <> -std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params) +AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params) { blockSubFields(params); - return resolve(std::move(result), - std::move(params), - [](response::FloatType&& value, const ResolverParams&) { - return response::Value(value); - }); + return resolve(std::move(result), std::move(params), [](double&& value, const ResolverParams&) { + return response::Value(value); + }); } template <> -std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params) +AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params) { blockSubFields(params); return resolve(std::move(result), std::move(params), - [](response::StringType&& value, const ResolverParams&) { + [](std::string&& value, const ResolverParams&) { return response::Value(std::move(value)); }); } template <> -std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params) +AwaitableResolver ModifiedResult::convert(AwaitableScalar result, ResolverParams params) { blockSubFields(params); - return resolve(std::move(result), - std::move(params), - [](response::BooleanType&& value, const ResolverParams&) { - return response::Value(value); - }); + return resolve(std::move(result), std::move(params), [](bool&& value, const ResolverParams&) { + return response::Value(value); + }); } template <> -std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params) +AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params) { blockSubFields(params); @@ -677,8 +665,8 @@ std::future ModifiedResult::convert( } template <> -std::future ModifiedResult::convert( - FieldResult&& result, ResolverParams&& params) +AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params) { blockSubFields(params); @@ -691,7 +679,7 @@ std::future ModifiedResult::convert( void requireSubFields(const ResolverParams& params) { - // http://spec.graphql.org/June2018/#sec-Leaf-Field-Selections + // https://spec.graphql.org/October2021/#sec-Leaf-Field-Selections if (params.selection == nullptr) { auto position = params.field.begin(); @@ -706,53 +694,87 @@ void requireSubFields(const ResolverParams& params) } template <> -std::future ModifiedResult::convert( - FieldResult>&& result, ResolverParams&& params) +AwaitableResolver ModifiedResult::convert( + AwaitableObject> result, ResolverParams params) { requireSubFields(params); - auto buildResult = [](FieldResult>&& resultFuture, - ResolverParams&& paramsFuture) { - auto wrappedResult = resultFuture.get(); + co_await params.launch; - if (!wrappedResult) - { - return ResolverResult {}; - } + auto awaitedResult = co_await std::move(result); - return wrappedResult - ->resolve(paramsFuture, - *paramsFuture.selection, - paramsFuture.fragments, - paramsFuture.variables) - .get(); - }; + if (!awaitedResult) + { + co_return ResolverResult {}; + } + + auto document = co_await awaitedResult->resolve(params, + *params.selection, + params.fragments, + params.variables); + + co_return std::move(document); +} + +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (value.type() != response::Type::Int) + { + throw schema_exception { { R"ex(not a valid Int value)ex" } }; + } +} + +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (value.type() != response::Type::Float) + { + throw schema_exception { { R"ex(not a valid Float value)ex" } }; + } +} - if (result.is_future()) +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (value.type() != response::Type::String) { - return std::async(params.launch, - std::move(buildResult), - std::move(result), - std::move(params)); + throw schema_exception { { R"ex(not a valid String value)ex" } }; } +} - std::promise promise; +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (value.type() != response::Type::Boolean) + { + throw schema_exception { { R"ex(not a valid Boolean value)ex" } }; + } +} - promise.set_value(buildResult(std::move(result), std::move(params))); +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (value.type() != response::Type::String) + { + throw schema_exception { { R"ex(not a valid String value)ex" } }; + } - return promise.get_future(); + try + { + const auto result = value.get(); + } + catch (const std::logic_error& ex) + { + throw schema_exception { { ex.what() } }; + } } -// As we recursively expand fragment spreads and inline fragments, we want to accumulate the -// directives at each location and merge them with any directives included in outer fragments to -// build the complete set of directives for nested fragments. Directives with the same name at the -// same location will be overwritten by the innermost fragment. -struct FragmentDirectives +template <> +void ModifiedResult::validateScalar(const response::Value&) { - response::Value fragmentDefinitionDirectives; - response::Value fragmentSpreadDirectives; - response::Value inlineFragmentDirectives; -}; + // Any response::Value is valid for a custom scalar type. +} // SelectionVisitor visits the AST and resolves a field or fragment, unless it's skipped by // a directive or type condition. @@ -765,7 +787,7 @@ class SelectionVisitor void visit(const peg::ast_node& selection); - std::vector>> getValues(); + std::vector> getValues(); private: void visitField(const peg::ast_node& field); @@ -774,17 +796,19 @@ class SelectionVisitor const ResolverContext _resolverContext; const std::shared_ptr& _state; - const response::Value& _operationDirectives; + const Directives& _operationDirectives; const std::optional> _path; - const std::launch _launch; + const await_async _launch; const FragmentMap& _fragments; const response::Value& _variables; const TypeNames& _typeNames; const ResolverMap& _resolvers; - std::list _fragmentDirectives; + std::shared_ptr _fragmentDefinitionDirectives; + std::shared_ptr _fragmentSpreadDirectives; + std::shared_ptr _inlineFragmentDirectives; internal::string_view_set _names; - std::vector>> _values; + std::vector> _values; }; SelectionVisitor::SelectionVisitor(const SelectionSetParams& selectionSetParams, @@ -801,16 +825,24 @@ SelectionVisitor::SelectionVisitor(const SelectionSetParams& selectionSetParams, , _variables(variables) , _typeNames(typeNames) , _resolvers(resolvers) + , _fragmentDefinitionDirectives { selectionSetParams.fragmentDefinitionDirectives } + , _fragmentSpreadDirectives { selectionSetParams.fragmentSpreadDirectives } + , _inlineFragmentDirectives { selectionSetParams.inlineFragmentDirectives } { - _fragmentDirectives.push_back({ response::Value(response::Type::Map), - response::Value(response::Type::Map), - response::Value(response::Type::Map) }); + static const Directives s_emptyFragmentDefinitionDirectives; + + // Traversing a SelectionSet from an Object type field should start tracking new fragment + // directives. The outer fragment directives are still there in the FragmentSpreadDirectiveStack + // if the field accessors want to inspect them. + _fragmentDefinitionDirectives->push_front(std::cref(s_emptyFragmentDefinitionDirectives)); + _fragmentSpreadDirectives->push_front({}); + _inlineFragmentDirectives->push_front({}); _names.reserve(count); _values.reserve(count); } -std::vector>> SelectionVisitor::getValues() +std::vector> SelectionVisitor::getValues() { auto values = std::move(_values); @@ -913,9 +945,9 @@ void SelectionVisitor::visitField(const peg::ast_node& field) _resolverContext, _state, _operationDirectives, - _fragmentDirectives.back().fragmentDefinitionDirectives, - _fragmentDirectives.back().fragmentSpreadDirectives, - _fragmentDirectives.back().inlineFragmentDirectives, + _fragmentDefinitionDirectives, + _fragmentSpreadDirectives, + _inlineFragmentDirectives, std::make_optional(field_path { _path, path_segment { alias } }), _launch, }; @@ -1008,33 +1040,8 @@ void SelectionVisitor::visitFragmentSpread(const peg::ast_node& fragmentSpread) return; } - auto fragmentSpreadDirectives = directiveVisitor.getDirectives(); - - // Merge outer fragment spread directives as long as they don't conflict. - for (const auto& entry : _fragmentDirectives.back().fragmentSpreadDirectives) - { - if (fragmentSpreadDirectives.find(entry.first) == fragmentSpreadDirectives.end()) - { - fragmentSpreadDirectives.emplace_back(std::string { entry.first }, - response::Value(entry.second)); - } - } - - response::Value fragmentDefinitionDirectives(itr->second.getDirectives()); - - // Merge outer fragment definition directives as long as they don't conflict. - for (const auto& entry : _fragmentDirectives.back().fragmentDefinitionDirectives) - { - if (fragmentDefinitionDirectives.find(entry.first) == fragmentDefinitionDirectives.end()) - { - fragmentDefinitionDirectives.emplace_back(std::string { entry.first }, - response::Value(entry.second)); - } - } - - _fragmentDirectives.push_back({ std::move(fragmentDefinitionDirectives), - std::move(fragmentSpreadDirectives), - response::Value(_fragmentDirectives.back().inlineFragmentDirectives) }); + _fragmentDefinitionDirectives->push_front(itr->second.getDirectives()); + _fragmentSpreadDirectives->push_front(directiveVisitor.getDirectives()); const size_t count = itr->second.getSelection().children.size(); @@ -1049,7 +1056,8 @@ void SelectionVisitor::visitFragmentSpread(const peg::ast_node& fragmentSpread) visit(*selection); } - _fragmentDirectives.pop_back(); + _fragmentSpreadDirectives->pop_front(); + _fragmentDefinitionDirectives->pop_front(); } void SelectionVisitor::visitInlineFragment(const peg::ast_node& inlineFragment) @@ -1078,23 +1086,7 @@ void SelectionVisitor::visitInlineFragment(const peg::ast_node& inlineFragment) { peg::on_first_child(inlineFragment, [this, &directiveVisitor](const peg::ast_node& child) { - auto inlineFragmentDirectives = directiveVisitor.getDirectives(); - - // Merge outer inline fragment directives as long as they don't conflict. - for (const auto& entry : _fragmentDirectives.back().inlineFragmentDirectives) - { - if (inlineFragmentDirectives.find(entry.first) - == inlineFragmentDirectives.end()) - { - inlineFragmentDirectives.emplace_back(std::string { entry.first }, - response::Value(entry.second)); - } - } - - _fragmentDirectives.push_back( - { response::Value(_fragmentDirectives.back().fragmentDefinitionDirectives), - response::Value(_fragmentDirectives.back().fragmentSpreadDirectives), - std::move(inlineFragmentDirectives) }); + _inlineFragmentDirectives->push_front(directiveVisitor.getDirectives()); const size_t count = child.children.size(); @@ -1109,18 +1101,18 @@ void SelectionVisitor::visitInlineFragment(const peg::ast_node& inlineFragment) visit(*selection); } - _fragmentDirectives.pop_back(); + _inlineFragmentDirectives->pop_front(); }); } } -Object::Object(TypeNames&& typeNames, ResolverMap&& resolvers) +Object::Object(TypeNames&& typeNames, ResolverMap&& resolvers) noexcept : _typeNames(std::move(typeNames)) , _resolvers(std::move(resolvers)) { } -std::future Object::resolve(const SelectionSetParams& selectionSetParams, +AwaitableResolver Object::resolve(const SelectionSetParams& selectionSetParams, const peg::ast_node& selection, const FragmentMap& fragments, const response::Value& variables) const { @@ -1140,62 +1132,59 @@ std::future Object::resolve(const SelectionSetParams& selectionS endSelectionSet(selectionSetParams); - return std::async( - selectionSetParams.launch, - [](std::vector>>&& children) { - ResolverResult document { response::Value { response::Type::Map } }; + auto children = visitor.getValues(); + const auto launch = selectionSetParams.launch; + ResolverResult document { response::Value { response::Type::Map } }; - document.data.reserve(children.size()); + document.data.reserve(children.size()); - for (auto& child : children) - { - auto name = child.first; + for (auto& child : children) + { + auto name = child.first; - try - { - auto value = child.second.get(); + try + { + co_await launch; - if (!document.data.emplace_back(std::string { name }, std::move(value.data))) - { - std::ostringstream message; + auto value = co_await std::move(child.second); - message << "Ambiguous field error name: " << name; + if (!document.data.emplace_back(std::string { name }, std::move(value.data))) + { + std::ostringstream message; - document.errors.push_back({ message.str() }); - } + message << "Ambiguous field error name: " << name; - if (!value.errors.empty()) - { - document.errors.splice(document.errors.end(), value.errors); - } - } - catch (schema_exception& scx) - { - auto errors = scx.getStructuredErrors(); + document.errors.push_back({ message.str() }); + } - if (!errors.empty()) - { - std::copy(errors.begin(), - errors.end(), - std::back_inserter(document.errors)); - } + if (!value.errors.empty()) + { + document.errors.splice(document.errors.end(), value.errors); + } + } + catch (schema_exception& scx) + { + auto errors = scx.getStructuredErrors(); - document.data.emplace_back(std::string { name }, {}); - } - catch (const std::exception& ex) - { - std::ostringstream message; + if (!errors.empty()) + { + std::copy(errors.begin(), errors.end(), std::back_inserter(document.errors)); + } - message << "Field error name: " << name << " unknown error: " << ex.what(); + document.data.emplace_back(std::string { name }, {}); + } + catch (const std::exception& ex) + { + std::ostringstream message; - document.errors.push_back({ message.str() }); - document.data.emplace_back(std::string { name }, {}); - } - } + message << "Field error name: " << name << " unknown error: " << ex.what(); + + document.errors.push_back({ message.str() }); + document.data.emplace_back(std::string { name }, {}); + } + } - return document; - }, - visitor.getValues()); + co_return std::move(document); } bool Object::matchesType(std::string_view typeName) const @@ -1211,8 +1200,8 @@ void Object::endSelectionSet(const SelectionSetParams&) const { } -OperationData::OperationData(std::shared_ptr&& state, response::Value&& variables, - response::Value&& directives, FragmentMap&& fragments) +OperationData::OperationData(std::shared_ptr state, response::Value variables, + Directives directives, FragmentMap fragments) : state(std::move(state)) , variables(std::move(variables)) , directives(std::move(directives)) @@ -1259,24 +1248,24 @@ void FragmentDefinitionVisitor::visit(const peg::ast_node& fragmentDefinition) class OperationDefinitionVisitor { public: - OperationDefinitionVisitor(ResolverContext resolverContext, std::launch launch, + OperationDefinitionVisitor(ResolverContext resolverContext, await_async launch, std::shared_ptr state, const TypeMap& operations, response::Value&& variables, FragmentMap&& fragments); - std::future getValue(); + AwaitableResolver getValue(); void visit(std::string_view operationType, const peg::ast_node& operationDefinition); private: const ResolverContext _resolverContext; - const std::launch _launch; + const await_async _launch; std::shared_ptr _params; const TypeMap& _operations; - std::future _result; + std::optional _result; }; -SubscriptionData::SubscriptionData(std::shared_ptr&& data, SubscriptionName&& field, - response::Value&& arguments, response::Value&& fieldDirectives, peg::ast&& query, +SubscriptionData::SubscriptionData(std::shared_ptr data, SubscriptionName&& field, + response::Value arguments, Directives fieldDirectives, peg::ast&& query, std::string&& operationName, SubscriptionCallback&& callback, const peg::ast_node& selection) : data(std::move(data)) , field(std::move(field)) @@ -1290,21 +1279,27 @@ SubscriptionData::SubscriptionData(std::shared_ptr&& data, Subscr } OperationDefinitionVisitor::OperationDefinitionVisitor(ResolverContext resolverContext, - std::launch launch, std::shared_ptr state, const TypeMap& operations, + await_async launch, std::shared_ptr state, const TypeMap& operations, response::Value&& variables, FragmentMap&& fragments) : _resolverContext(resolverContext) , _launch(launch) , _params(std::make_shared( - std::move(state), std::move(variables), response::Value(), std::move(fragments))) + std::move(state), std::move(variables), Directives {}, std::move(fragments))) , _operations(operations) { } -std::future OperationDefinitionVisitor::getValue() +AwaitableResolver OperationDefinitionVisitor::getValue() { - auto result = std::move(_result); + if (!_result) + { + co_return ResolverResult {}; + } - return result; + auto result = std::move(*_result); + + co_await _launch; + co_return co_await result; } void OperationDefinitionVisitor::visit( @@ -1348,7 +1343,7 @@ void OperationDefinitionVisitor::visit( _params->variables = std::move(operationVariables); - response::Value operationDirectives(response::Type::Map); + Directives operationDirectives; peg::on_first_child(operationDefinition, [this, &operationDirectives](const peg::ast_node& child) { @@ -1360,32 +1355,21 @@ void OperationDefinitionVisitor::visit( _params->directives = std::move(operationDirectives); - // Keep the params alive until the deferred lambda has executed - _result = std::async( + const SelectionSetParams selectionSetParams { + _resolverContext, + _params->state, + _params->directives, + std::make_shared(), + std::make_shared(), + std::make_shared(), + std::nullopt, _launch, - [selectionContext = _resolverContext, - selectionLaunch = _launch, - params = std::move(_params), - operation = itr->second](const peg::ast_node& selection) { - // The top level object doesn't come from inside of a fragment, so all of the fragment - // directives are empty. - const response::Value emptyFragmentDirectives(response::Type::Map); - const SelectionSetParams selectionSetParams { - selectionContext, - params->state, - params->directives, - emptyFragmentDirectives, - emptyFragmentDirectives, - emptyFragmentDirectives, - std::nullopt, - selectionLaunch, - }; + }; - return operation - ->resolve(selectionSetParams, selection, params->fragments, params->variables) - .get(); - }, - std::cref(*operationDefinition.children.back())); + _result = std::make_optional(itr->second->resolve(selectionSetParams, + *operationDefinition.children.back(), + _params->fragments, + _params->variables)); } // SubscriptionDefinitionVisitor visits the AST collects the fields referenced in the subscription @@ -1393,8 +1377,8 @@ void OperationDefinitionVisitor::visit( class SubscriptionDefinitionVisitor { public: - SubscriptionDefinitionVisitor(SubscriptionParams&& params, SubscriptionCallback&& callback, - FragmentMap&& fragments, const std::shared_ptr& subscriptionObject); + SubscriptionDefinitionVisitor(RequestSubscribeParams&& params, FragmentMap&& fragments, + const std::shared_ptr& subscriptionObject); const peg::ast_node& getRoot() const; std::shared_ptr getRegistration(); @@ -1406,21 +1390,18 @@ class SubscriptionDefinitionVisitor void visitFragmentSpread(const peg::ast_node& fragmentSpread); void visitInlineFragment(const peg::ast_node& inlineFragment); - SubscriptionParams _params; - SubscriptionCallback _callback; + RequestSubscribeParams _params; FragmentMap _fragments; const std::shared_ptr& _subscriptionObject; SubscriptionName _field; response::Value _arguments; - response::Value _fieldDirectives; + Directives _fieldDirectives; std::shared_ptr _result; }; -SubscriptionDefinitionVisitor::SubscriptionDefinitionVisitor(SubscriptionParams&& params, - SubscriptionCallback&& callback, FragmentMap&& fragments, - const std::shared_ptr& subscriptionObject) +SubscriptionDefinitionVisitor::SubscriptionDefinitionVisitor(RequestSubscribeParams&& params, + FragmentMap&& fragments, const std::shared_ptr& subscriptionObject) : _params(std::move(params)) - , _callback(std::move(callback)) , _fragments(std::move(fragments)) , _subscriptionObject(subscriptionObject) { @@ -1460,7 +1441,7 @@ void SubscriptionDefinitionVisitor::visit(const peg::ast_node& operationDefiniti } } - response::Value directives(response::Type::Map); + Directives directives; peg::on_first_child(operationDefinition, [this, &directives](const peg::ast_node& child) { @@ -1480,7 +1461,7 @@ void SubscriptionDefinitionVisitor::visit(const peg::ast_node& operationDefiniti std::move(_fieldDirectives), std::move(_params.query), std::move(_params.operationName), - std::move(_callback), + std::move(_params.callback), selection); } @@ -1492,7 +1473,7 @@ void SubscriptionDefinitionVisitor::visitField(const peg::ast_node& field) name = child.string_view(); }); - // http://spec.graphql.org/June2018/#sec-Single-root-field + // https://spec.graphql.org/October2021/#sec-Single-root-field if (!_field.empty()) { auto position = field.begin(); @@ -1609,9 +1590,9 @@ void SubscriptionDefinitionVisitor::visitInlineFragment(const peg::ast_node& inl } } -Request::Request(TypeMap&& operationTypes, const std::shared_ptr& schema) +Request::Request(TypeMap operationTypes, std::shared_ptr schema) : _operations(std::move(operationTypes)) - , _validation(std::make_unique(schema)) + , _validation(std::make_unique(std::move(schema))) { } @@ -1677,27 +1658,19 @@ std::pair Request::findOperationDefiniti return result; } -std::future Request::resolve(const std::shared_ptr& state, - peg::ast& query, const std::string& operationName, response::Value&& variables) const -{ - return resolve(std::launch::deferred, state, query, operationName, std::move(variables)); -} - -std::future Request::resolve(std::launch launch, - const std::shared_ptr& state, peg::ast& query, const std::string& operationName, - response::Value&& variables) const +response::AwaitableValue Request::resolve(RequestResolveParams params) const { try { - FragmentDefinitionVisitor fragmentVisitor(variables); + FragmentDefinitionVisitor fragmentVisitor(params.variables); - peg::for_each_child(*query.root, + peg::for_each_child(*params.query.root, [&fragmentVisitor](const peg::ast_node& child) { fragmentVisitor.visit(child); }); auto fragments = fragmentVisitor.getFragments(); - auto operationDefinition = findOperationDefinition(query, operationName); + auto operationDefinition = findOperationDefinition(params.query, params.operationName); if (!operationDefinition.second) { @@ -1705,9 +1678,9 @@ std::future Request::resolve(std::launch launch, message << "Missing operation"; - if (!operationName.empty()) + if (!params.operationName.empty()) { - message << " name: " << operationName; + message << " name: " << params.operationName; } throw schema_exception { { message.str() } }; @@ -1719,9 +1692,9 @@ std::future Request::resolve(std::launch launch, message << "Unexpected subscription"; - if (!operationName.empty()) + if (!params.operationName.empty()) { - message << " name: " << operationName; + message << " name: " << params.operationName; } throw schema_exception { @@ -1732,204 +1705,190 @@ std::future Request::resolve(std::launch launch, const bool isMutation = (operationDefinition.first == strMutation); const auto resolverContext = isMutation ? ResolverContext::Mutation : ResolverContext::Query; - // http://spec.graphql.org/June2018/#sec-Normal-and-Serial-Execution - const auto operationLaunch = isMutation ? std::launch::deferred : launch; + // https://spec.graphql.org/October2021/#sec-Normal-and-Serial-Execution + const auto operationLaunch = isMutation ? await_async {} : params.launch; OperationDefinitionVisitor operationVisitor(resolverContext, - operationLaunch, - state, + std::move(operationLaunch), + std::move(params.state), _operations, - std::move(variables), + std::move(params.variables), std::move(fragments)); operationVisitor.visit(operationDefinition.first, *operationDefinition.second); - return std::async( - launch, - [](std::future&& operationFuture) { - auto result = operationFuture.get(); - response::Value document { response::Type::Map }; + co_await params.launch; - document.emplace_back(std::string { strData }, std::move(result.data)); + auto result = co_await operationVisitor.getValue(); + response::Value document { response::Type::Map }; - if (!result.errors.empty()) - { - document.emplace_back(std::string { strErrors }, - buildErrorValues(std::move(result.errors))); - } + document.emplace_back(std::string { strData }, std::move(result.data)); + + if (!result.errors.empty()) + { + document.emplace_back(std::string { strErrors }, + buildErrorValues(std::move(result.errors))); + } - return document; - }, - operationVisitor.getValue()); + co_return std::move(document); } catch (schema_exception& ex) { - std::promise promise; response::Value document(response::Type::Map); document.emplace_back(std::string { strData }, response::Value()); document.emplace_back(std::string { strErrors }, ex.getErrors()); - promise.set_value(std::move(document)); - return promise.get_future(); + co_return std::move(document); } } -std::pair Request::findOperationDefinition( - const peg::ast_node& root, const std::string& operationName) const -{ - return findUnvalidatedOperationDefinition(root, operationName); -} - -std::pair Request::findUnvalidatedOperationDefinition( - const peg::ast_node& root, const std::string& operationName) const +AwaitableSubscribe Request::subscribe(RequestSubscribeParams params) { - std::pair result = { {}, nullptr }; + const auto spThis = shared_from_this(); + auto launch = params.launch; + const auto key = spThis->addSubscription(std::move(params)); + const auto itrOperation = spThis->_operations.find(strSubscription); - peg::on_first_child_if(root, - [&operationName, &result](const peg::ast_node& operationDefinition) { - auto operationType = strQuery; + if (itrOperation != spThis->_operations.end()) + { + const auto& operation = itrOperation->second; + const auto& registration = spThis->_subscriptions.at(key); + const SelectionSetParams selectionSetParams { + ResolverContext::NotifySubscribe, + registration->data->state, + registration->data->directives, + std::make_shared(), + std::make_shared(), + std::make_shared(), + {}, + launch, + }; - peg::on_first_child(operationDefinition, - [&operationType](const peg::ast_node& child) { - operationType = child.string_view(); - }); + try + { + co_await launch; + co_await operation->resolve(selectionSetParams, + registration->selection, + registration->data->fragments, + registration->data->variables); + } + catch (const std::exception& ex) + { + // Rethrow the exception, but don't leave it subscribed if the resolver failed. + spThis->removeSubscription(key); + throw ex; + } + } - std::string_view name; + co_return key; +} - peg::on_first_child(operationDefinition, - [&name](const peg::ast_node& child) { - name = child.string_view(); - }); +AwaitableUnsubscribe Request::unsubscribe(RequestUnsubscribeParams params) +{ + const auto spThis = shared_from_this(); + const auto itrOperation = spThis->_operations.find(strSubscription); - if (operationName.empty() || name == operationName) - { - result = { std::string { operationType }, &operationDefinition }; - return true; - } + if (itrOperation != spThis->_operations.end()) + { + const auto& operation = itrOperation->second; + const auto& registration = spThis->_subscriptions.at(params.key); + const SelectionSetParams selectionSetParams { + ResolverContext::NotifyUnsubscribe, + registration->data->state, + registration->data->directives, + std::make_shared(), + std::make_shared(), + std::make_shared(), + {}, + params.launch, + }; - return false; - }); + co_await params.launch; + co_await operation->resolve(selectionSetParams, + registration->selection, + registration->data->fragments, + registration->data->variables); + } - return result; -} + spThis->removeSubscription(params.key); -std::future Request::resolve(const std::shared_ptr& state, - const peg::ast_node& root, const std::string& operationName, response::Value&& variables) const -{ - return resolveUnvalidated(std::launch::deferred, - state, - root, - operationName, - std::move(variables)); + co_return; } -std::future Request::resolve(std::launch launch, - const std::shared_ptr& state, const peg::ast_node& root, - const std::string& operationName, response::Value&& variables) const +AwaitableDeliver Request::deliver(RequestDeliverParams params) const { - return resolveUnvalidated(launch, state, root, operationName, std::move(variables)); -} + const auto itrOperation = _operations.find(strSubscription); -std::future Request::resolveUnvalidated(std::launch launch, - const std::shared_ptr& state, const peg::ast_node& root, - const std::string& operationName, response::Value&& variables) const -{ - try + if (itrOperation == _operations.end()) { - FragmentDefinitionVisitor fragmentVisitor(variables); + // There may be an empty entry in the operations map, but if it's completely missing then + // that means the schema doesn't support subscriptions at all. + throw std::logic_error("Subscriptions not supported"); + } - peg::for_each_child(root, - [&fragmentVisitor](const peg::ast_node& child) { - fragmentVisitor.visit(child); - }); + const auto optionalOrDefaultSubscription = + params.subscriptionObject ? std::move(params.subscriptionObject) : itrOperation->second; - auto fragments = fragmentVisitor.getFragments(); - auto operationDefinition = findUnvalidatedOperationDefinition(root, operationName); + if (!optionalOrDefaultSubscription) + { + // If there is no default in the operations map, you must pass a non-empty + // subscriptionObject parameter to deliver. + throw std::invalid_argument("Missing subscriptionObject"); + } - if (!operationDefinition.second) - { - std::ostringstream message; + const auto registrations = collectRegistrations(params.field, std::move(params.filter)); - message << "Missing operation"; + if (registrations.empty()) + { + co_return; + } - if (!operationName.empty()) - { - message << " name: " << operationName; - } + for (const auto& registration : registrations) + { + const SelectionSetParams selectionSetParams { + ResolverContext::Subscription, + registration->data->state, + registration->data->directives, + std::make_shared(), + std::make_shared(), + std::make_shared(), + std::nullopt, + params.launch, + }; - throw schema_exception { { message.str() } }; - } - else if (operationDefinition.first == strSubscription) + response::Value document { response::Type::Map }; + + try { - auto position = operationDefinition.second->begin(); - std::ostringstream message; + co_await params.launch; - message << "Unexpected subscription"; + auto result = co_await optionalOrDefaultSubscription->resolve(selectionSetParams, + registration->selection, + registration->data->fragments, + registration->data->variables); - if (!operationName.empty()) + document.emplace_back(std::string { strData }, std::move(result.data)); + + if (!result.errors.empty()) { - message << " name: " << operationName; + document.emplace_back(std::string { strErrors }, + buildErrorValues(std::move(result.errors))); } - - throw schema_exception { - { schema_error { message.str(), { position.line, position.column } } } - }; } - - const bool isMutation = (operationDefinition.first == strMutation); - - // http://spec.graphql.org/June2018/#sec-Normal-and-Serial-Execution - if (isMutation) + catch (schema_exception& ex) { - // Force mutations to perform serial execution - launch = std::launch::deferred; + document.emplace_back(std::string { strData }, response::Value()); + document.emplace_back(std::string { strErrors }, ex.getErrors()); } - const auto resolverContext = - isMutation ? ResolverContext::Mutation : ResolverContext::Query; - - OperationDefinitionVisitor operationVisitor(resolverContext, - launch, - state, - _operations, - std::move(variables), - std::move(fragments)); - - operationVisitor.visit(operationDefinition.first, *operationDefinition.second); - - return std::async( - launch, - [](std::future&& operationFuture) { - auto result = operationFuture.get(); - response::Value document { response::Type::Map }; - - document.emplace_back(std::string { strData }, std::move(result.data)); - - if (!result.errors.empty()) - { - document.emplace_back(std::string { strErrors }, - buildErrorValues(std::move(result.errors))); - } - - return document; - }, - operationVisitor.getValue()); + registration->callback(std::move(document)); } - catch (schema_exception& ex) - { - std::promise promise; - response::Value document(response::Type::Map); - - document.emplace_back(std::string { strData }, response::Value()); - document.emplace_back(std::string { strErrors }, ex.getErrors()); - promise.set_value(std::move(document)); - return promise.get_future(); - } + co_return; } -SubscriptionKey Request::subscribe(SubscriptionParams&& params, SubscriptionCallback&& callback) +SubscriptionKey Request::addSubscription(RequestSubscribeParams&& params) { auto errors = validate(params.query); @@ -1980,7 +1939,6 @@ SubscriptionKey Request::subscribe(SubscriptionParams&& params, SubscriptionCall auto itr = _operations.find(strSubscription); SubscriptionDefinitionVisitor subscriptionVisitor(std::move(params), - std::move(callback), std::move(fragments), itr->second); @@ -1998,56 +1956,7 @@ SubscriptionKey Request::subscribe(SubscriptionParams&& params, SubscriptionCall return key; } -std::future Request::subscribe( - std::launch launch, SubscriptionParams&& params, SubscriptionCallback&& callback) -{ - return std::async( - launch, - [spThis = shared_from_this(), launch](SubscriptionParams&& paramsFuture, - SubscriptionCallback&& callbackFuture) { - const auto key = spThis->subscribe(std::move(paramsFuture), std::move(callbackFuture)); - const auto itrOperation = spThis->_operations.find(strSubscription); - - if (itrOperation != spThis->_operations.end()) - { - const auto& operation = itrOperation->second; - const auto& registration = spThis->_subscriptions.at(key); - response::Value emptyFragmentDirectives(response::Type::Map); - const SelectionSetParams selectionSetParams { - ResolverContext::NotifySubscribe, - registration->data->state, - registration->data->directives, - emptyFragmentDirectives, - emptyFragmentDirectives, - emptyFragmentDirectives, - {}, - launch, - }; - - try - { - operation - ->resolve(selectionSetParams, - registration->selection, - registration->data->fragments, - registration->data->variables) - .get(); - } - catch (const std::exception& ex) - { - // Rethrow the exception, but don't leave it subscribed if the resolver failed. - spThis->unsubscribe(key); - throw ex; - } - } - - return key; - }, - std::move(params), - std::move(callback)); -} - -void Request::unsubscribe(SubscriptionKey key) +void Request::removeSubscription(SubscriptionKey key) { auto itrSubscription = _subscriptions.find(key); @@ -2077,256 +1986,149 @@ void Request::unsubscribe(SubscriptionKey key) } } -std::future Request::unsubscribe(std::launch launch, SubscriptionKey key) +std::vector> Request::collectRegistrations( + std::string_view field, RequestDeliverFilter&& filter) const noexcept { - return std::async(launch, [spThis = shared_from_this(), launch, key]() { - const auto itrOperation = spThis->_operations.find(strSubscription); + std::vector> registrations; + const auto itrListeners = _listeners.find(field); - if (itrOperation != spThis->_operations.end()) + if (itrListeners != _listeners.end()) + { + if (!filter) { - const auto& operation = itrOperation->second; - const auto& registration = spThis->_subscriptions.at(key); - response::Value emptyFragmentDirectives(response::Type::Map); - const SelectionSetParams selectionSetParams { - ResolverContext::NotifyUnsubscribe, - registration->data->state, - registration->data->directives, - emptyFragmentDirectives, - emptyFragmentDirectives, - emptyFragmentDirectives, - {}, - launch, - }; - - operation - ->resolve(selectionSetParams, - registration->selection, - registration->data->fragments, - registration->data->variables) - .get(); + // Return all of the registered subscriptions for this field. + registrations.reserve(itrListeners->second.size()); + std::transform(itrListeners->second.begin(), + itrListeners->second.end(), + std::back_inserter(registrations), + [this](const auto& key) noexcept { + const auto itr = _subscriptions.find(key); + + return itr == _subscriptions.end() ? std::shared_ptr {} + : itr->second; + }); } - - spThis->unsubscribe(key); - }); -} - -void Request::deliver( - const SubscriptionName& name, const std::shared_ptr& subscriptionObject) const -{ - deliver(std::launch::deferred, name, subscriptionObject); -} - -void Request::deliver(const SubscriptionName& name, const SubscriptionArguments& arguments, - const std::shared_ptr& subscriptionObject) const -{ - deliver(std::launch::deferred, name, arguments, subscriptionObject); -} - -void Request::deliver(const SubscriptionName& name, const SubscriptionArguments& arguments, - const SubscriptionArguments& directives, - const std::shared_ptr& subscriptionObject) const -{ - deliver(std::launch::deferred, name, arguments, directives, subscriptionObject); -} - -void Request::deliver(const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const std::shared_ptr& subscriptionObject) const -{ - deliver(std::launch::deferred, name, applyArguments, subscriptionObject); -} - -void Request::deliver(const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const SubscriptionFilterCallback& applyDirectives, - const std::shared_ptr& subscriptionObject) const -{ - deliver(std::launch::deferred, name, applyArguments, applyDirectives, subscriptionObject); -} - -void Request::deliver(std::launch launch, const SubscriptionName& name, - const std::shared_ptr& subscriptionObject) const -{ - deliver(launch, name, SubscriptionArguments {}, SubscriptionArguments {}, subscriptionObject); -} - -void Request::deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionArguments& arguments, const std::shared_ptr& subscriptionObject) const -{ - deliver(launch, name, arguments, SubscriptionArguments {}, subscriptionObject); -} - -void Request::deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionArguments& arguments, const SubscriptionArguments& directives, - const std::shared_ptr& subscriptionObject) const -{ - SubscriptionFilterCallback argumentsMatch = - [&arguments](response::MapType::const_reference required) noexcept -> bool { - auto itrArgument = arguments.find(required.first); - - return (itrArgument != arguments.end() && itrArgument->second == required.second); - }; - - SubscriptionFilterCallback directivesMatch = - [&directives](response::MapType::const_reference required) noexcept -> bool { - auto itrDirective = directives.find(required.first); - - return (itrDirective != directives.end() && itrDirective->second == required.second); - }; - - deliver(launch, name, argumentsMatch, directivesMatch, subscriptionObject); -} - -void Request::deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const std::shared_ptr& subscriptionObject) const -{ - deliver( - launch, - name, - applyArguments, - [](response::MapType::const_reference) noexcept { - return true; - }, - subscriptionObject); -} - -void Request::deliver(std::launch launch, const SubscriptionName& name, - const SubscriptionFilterCallback& applyArguments, - const SubscriptionFilterCallback& applyDirectives, - const std::shared_ptr& subscriptionObject) const -{ - const auto itrOperation = _operations.find(strSubscription); - - if (itrOperation == _operations.end()) - { - // There may be an empty entry in the operations map, but if it's completely missing then - // that means the schema doesn't support subscriptions at all. - throw std::logic_error("Subscriptions not supported"); - } - - const auto& optionalOrDefaultSubscription = - subscriptionObject ? subscriptionObject : itrOperation->second; - - if (!optionalOrDefaultSubscription) - { - // If there is no default in the operations map, you must pass a non-empty - // subscriptionObject parameter to deliver. - throw std::invalid_argument("Missing subscriptionObject"); - } - - auto itrListeners = _listeners.find(name); - - if (itrListeners == _listeners.end()) - { - return; - } - - std::vector> callbacks; - - callbacks.reserve(itrListeners->second.size()); - for (const auto& key : itrListeners->second) - { - auto itrSubscription = _subscriptions.find(key); - auto registration = itrSubscription->second; - const auto& subscriptionArguments = registration->arguments; - bool matchedArguments = true; - - // If the field in this subscription had arguments that did not match what was provided - // in this event, don't deliver the event to this subscription - for (const auto& required : subscriptionArguments) + else if (std::holds_alternative(*filter)) { - if (!applyArguments(required)) + // Return the specific subscription for this key. + const auto itr = _subscriptions.find(std::get(*filter)); + + if (itr != _subscriptions.end() && itr->second->field == field) { - matchedArguments = false; - break; + registrations.push_back(itr->second); } } - - if (!matchedArguments) + else if (std::holds_alternative(*filter)) { - continue; - } + auto& subscriptionFilter = std::get(*filter); - // If the field in this subscription had field directives that did not match what was - // provided in this event, don't deliver the event to this subscription - const auto& subscriptionFieldDirectives = registration->fieldDirectives; - bool matchedFieldDirectives = true; + registrations.reserve(itrListeners->second.size()); - for (const auto& required : subscriptionFieldDirectives) - { - if (!applyDirectives(required)) + std::optional argumentsMatch; + + if (subscriptionFilter.arguments) { - matchedFieldDirectives = false; - break; + if (std::holds_alternative(*subscriptionFilter.arguments)) + { + argumentsMatch = [arguments = std::move(std::get( + *subscriptionFilter.arguments))]( + response::MapType::const_reference required) noexcept { + auto itrArgument = arguments.find(required.first); + + return (itrArgument != arguments.end() + && itrArgument->second == required.second); + }; + } + else if (std::holds_alternative( + *subscriptionFilter.arguments)) + { + argumentsMatch = std::move(std::get( + *subscriptionFilter.arguments)); + } } - } - if (!matchedFieldDirectives) - { - continue; - } + std::optional directivesMatch; - std::future result; - response::Value emptyFragmentDirectives(response::Type::Map); - const SelectionSetParams selectionSetParams { - ResolverContext::Subscription, - registration->data->state, - registration->data->directives, - emptyFragmentDirectives, - emptyFragmentDirectives, - emptyFragmentDirectives, - std::nullopt, - launch, - }; + if (subscriptionFilter.directives) + { + if (std::holds_alternative(*subscriptionFilter.directives)) + { + directivesMatch = [directives = std::move( + std::get(*subscriptionFilter.directives))]( + Directives::const_reference required) noexcept { + auto itrDirective = std::find_if(directives.cbegin(), + directives.cend(), + [directiveName = required.first](const auto& directive) noexcept { + return directive.first == directiveName; + }); + + return (itrDirective != directives.end() + && itrDirective->second == required.second); + }; + } + else if (std::holds_alternative( + *subscriptionFilter.directives)) + { + directivesMatch = std::move(std::get( + *subscriptionFilter.directives)); + } + } - try - { - result = std::async( - launch, - [](std::future&& operationFuture) { - auto result = operationFuture.get(); - response::Value document { response::Type::Map }; + for (const auto& key : itrListeners->second) + { + auto itrSubscription = _subscriptions.find(key); + auto registration = itrSubscription->second; - document.emplace_back(std::string { strData }, std::move(result.data)); + if (argumentsMatch) + { + const auto& subscriptionArguments = registration->arguments; + bool matchedArguments = true; - if (!result.errors.empty()) + // If the field in this subscription had arguments that did not match what was + // provided in this event, don't deliver the event to this subscription + for (const auto& required : subscriptionArguments) { - document.emplace_back(std::string { strErrors }, - buildErrorValues(std::move(result.errors))); + if (!(*argumentsMatch)(required)) + { + matchedArguments = false; + break; + } } - return document; - }, - optionalOrDefaultSubscription->resolve(selectionSetParams, - registration->selection, - registration->data->fragments, - registration->data->variables)); - } - catch (schema_exception& ex) - { - std::promise promise; - response::Value document(response::Type::Map); + if (!matchedArguments) + { + continue; + } + } - document.emplace_back(std::string { strData }, response::Value()); - document.emplace_back(std::string { strErrors }, ex.getErrors()); - promise.set_value(std::move(document)); + if (directivesMatch) + { + // If the field in this subscription had field directives that did not match + // what was provided in this event, don't deliver the event to this subscription + const auto& subscriptionFieldDirectives = registration->fieldDirectives; + bool matchedFieldDirectives = true; - result = promise.get_future(); - } + for (const auto& required : subscriptionFieldDirectives) + { + if (!(*directivesMatch)(required)) + { + matchedFieldDirectives = false; + break; + } + } - callbacks.push_back(std::async( - launch, - [registration](std::future document) { - registration->callback(std::move(document)); - }, - std::move(result))); - } + if (!matchedFieldDirectives) + { + continue; + } + } - for (auto& callback : callbacks) - { - callback.get(); + registrations.push_back(std::move(registration)); + } + } } + + return registrations; } } // namespace graphql::service diff --git a/src/Introspection.cpp b/src/Introspection.cpp index 44116409..5ac539e9 100644 --- a/src/Introspection.cpp +++ b/src/Introspection.cpp @@ -1,7 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "graphqlservice/introspection/Introspection.h" +#include "graphqlservice/internal/Introspection.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +#include "graphqlservice/introspection/DirectiveObject.h" +#include "graphqlservice/introspection/EnumValueObject.h" +#include "graphqlservice/introspection/FieldObject.h" +#include "graphqlservice/introspection/InputValueObject.h" +#include "graphqlservice/introspection/SchemaObject.h" +#include "graphqlservice/introspection/TypeObject.h" namespace graphql::introspection { @@ -10,51 +19,56 @@ Schema::Schema(const std::shared_ptr& schema) { } -service::FieldResult>> Schema::getTypes( - service::FieldParams&&) const +std::optional Schema::getDescription() const +{ + const auto description = _schema->description(); + + return { description.empty() ? std::nullopt : std::make_optional(description) }; +} + +std::vector> Schema::getTypes() const { const auto& types = _schema->types(); std::vector> result(types.size()); std::transform(types.begin(), types.end(), result.begin(), [](const auto& entry) { - return std::make_shared(entry.second); + return std::make_shared(std::make_shared(entry.second)); }); return result; } -service::FieldResult> Schema::getQueryType( - service::FieldParams&&) const +std::shared_ptr Schema::getQueryType() const { const auto& queryType = _schema->queryType(); - return queryType ? std::make_shared(queryType) : nullptr; + return queryType ? std::make_shared(std::make_shared(queryType)) : nullptr; } -service::FieldResult> Schema::getMutationType( - service::FieldParams&&) const +std::shared_ptr Schema::getMutationType() const { const auto& mutationType = _schema->mutationType(); - return mutationType ? std::make_shared(mutationType) : nullptr; + return mutationType ? std::make_shared(std::make_shared(mutationType)) + : nullptr; } -service::FieldResult> Schema::getSubscriptionType( - service::FieldParams&&) const +std::shared_ptr Schema::getSubscriptionType() const { const auto& subscriptionType = _schema->subscriptionType(); - return subscriptionType ? std::make_shared(subscriptionType) : nullptr; + return subscriptionType + ? std::make_shared(std::make_shared(subscriptionType)) + : nullptr; } -service::FieldResult>> Schema::getDirectives( - service::FieldParams&&) const +std::vector> Schema::getDirectives() const { const auto& directives = _schema->directives(); std::vector> result(directives.size()); std::transform(directives.begin(), directives.end(), result.begin(), [](const auto& entry) { - return std::make_shared(entry); + return std::make_shared(std::make_shared(entry)); }); return result; @@ -65,30 +79,27 @@ Type::Type(const std::shared_ptr& type) { } -service::FieldResult Type::getKind(service::FieldParams&&) const +TypeKind Type::getKind() const { return _type->kind(); } -service::FieldResult> Type::getName( - service::FieldParams&&) const +std::optional Type::getName() const { const auto name = _type->name(); - return { name.empty() ? std::nullopt : std::make_optional(name) }; + return { name.empty() ? std::nullopt : std::make_optional(name) }; } -service::FieldResult> Type::getDescription( - service::FieldParams&&) const +std::optional Type::getDescription() const { const auto description = _type->description(); - return { description.empty() ? std::nullopt - : std::make_optional(description) }; + return { description.empty() ? std::nullopt : std::make_optional(description) }; } -service::FieldResult>>> Type::getFields( - service::FieldParams&&, std::optional&& includeDeprecatedArg) const +std::optional>> Type::getFields( + std::optional&& includeDeprecatedArg) const { switch (_type->kind()) { @@ -109,15 +120,14 @@ service::FieldResult>>> { if (deprecated || !field->deprecationReason()) { - result->push_back(std::make_shared(field)); + result->push_back(std::make_shared(std::make_shared(field))); } } return result; } -service::FieldResult>>> Type::getInterfaces( - service::FieldParams&&) const +std::optional>> Type::getInterfaces() const { switch (_type->kind()) { @@ -132,14 +142,13 @@ service::FieldResult>>> auto result = std::make_optional>>(interfaces.size()); std::transform(interfaces.begin(), interfaces.end(), result->begin(), [](const auto& entry) { - return std::make_shared(entry); + return std::make_shared(std::make_shared(entry)); }); return result; } -service::FieldResult>>> Type:: - getPossibleTypes(service::FieldParams&&) const +std::optional>> Type::getPossibleTypes() const { switch (_type->kind()) { @@ -159,15 +168,21 @@ service::FieldResult>>> possibleTypes.end(), result->begin(), [](const auto& entry) { - return std::make_shared(entry.lock()); + auto typeEntry = entry.lock(); + + return typeEntry && typeEntry->kind() == introspection::TypeKind::OBJECT + ? std::make_shared(std::make_shared(std::move(typeEntry))) + : std::shared_ptr {}; }); + result->erase(std::remove(result->begin(), result->end(), std::shared_ptr {}), + result->cend()); + return result; } -service::FieldResult>>> Type:: - getEnumValues( - service::FieldParams&&, std::optional&& includeDeprecatedArg) const +std::optional>> Type::getEnumValues( + std::optional&& includeDeprecatedArg) const { switch (_type->kind()) { @@ -187,15 +202,15 @@ service::FieldResultdeprecationReason()) { - result->push_back(std::make_shared(value)); + result->push_back( + std::make_shared(std::make_shared(value))); } } return result; } -service::FieldResult>>> Type:: - getInputFields(service::FieldParams&&) const +std::optional>> Type::getInputFields() const { switch (_type->kind()) { @@ -211,13 +226,13 @@ service::FieldResult>>(inputFields.size()); std::transform(inputFields.begin(), inputFields.end(), result->begin(), [](const auto& entry) { - return std::make_shared(entry); + return std::make_shared(std::make_shared(entry)); }); return result; } -service::FieldResult> Type::getOfType(service::FieldParams&&) const +std::shared_ptr Type::getOfType() const { switch (_type->kind()) { @@ -231,7 +246,15 @@ service::FieldResult> Type::getOfType(service::Fie const auto ofType = _type->ofType().lock(); - return ofType ? std::make_shared(ofType) : nullptr; + return ofType ? std::make_shared(std::make_shared(ofType)) : nullptr; +} + +std::optional Type::getSpecifiedByURL() const +{ + const auto specifiedByURL = _type->specifiedByURL(); + + return { specifiedByURL.empty() ? std::nullopt + : std::make_optional(specifiedByURL) }; } Field::Field(const std::shared_ptr& field) @@ -239,51 +262,47 @@ Field::Field(const std::shared_ptr& field) { } -service::FieldResult Field::getName(service::FieldParams&&) const +std::string Field::getName() const { - return response::StringType { _field->name() }; + return std::string { _field->name() }; } -service::FieldResult> Field::getDescription( - service::FieldParams&&) const +std::optional Field::getDescription() const { const auto description = _field->description(); - return { description.empty() ? std::nullopt - : std::make_optional(description) }; + return { description.empty() ? std::nullopt : std::make_optional(description) }; } -service::FieldResult>> Field::getArgs( - service::FieldParams&&) const +std::vector> Field::getArgs() const { const auto& args = _field->args(); std::vector> result(args.size()); std::transform(args.begin(), args.end(), result.begin(), [](const auto& entry) { - return std::make_shared(entry); + return std::make_shared(std::make_shared(entry)); }); return result; } -service::FieldResult> Field::getType(service::FieldParams&&) const +std::shared_ptr Field::getType() const { const auto type = _field->type().lock(); - return type ? std::make_shared(type) : nullptr; + return type ? std::make_shared(std::make_shared(type)) : nullptr; } -service::FieldResult Field::getIsDeprecated(service::FieldParams&&) const +bool Field::getIsDeprecated() const { return _field->deprecationReason().has_value(); } -service::FieldResult> Field::getDeprecationReason( - service::FieldParams&&) const +std::optional Field::getDeprecationReason() const { const auto& deprecationReason = _field->deprecationReason(); - return { deprecationReason ? std::make_optional(*deprecationReason) + return { deprecationReason ? std::make_optional(*deprecationReason) : std::nullopt }; } @@ -292,35 +311,30 @@ InputValue::InputValue(const std::shared_ptr& inputVal { } -service::FieldResult InputValue::getName(service::FieldParams&&) const +std::string InputValue::getName() const { - return response::StringType { _inputValue->name() }; + return std::string { _inputValue->name() }; } -service::FieldResult> InputValue::getDescription( - service::FieldParams&&) const +std::optional InputValue::getDescription() const { const auto description = _inputValue->description(); - return { description.empty() ? std::nullopt - : std::make_optional(description) }; + return { description.empty() ? std::nullopt : std::make_optional(description) }; } -service::FieldResult> InputValue::getType( - service::FieldParams&&) const +std::shared_ptr InputValue::getType() const { const auto type = _inputValue->type().lock(); - return type ? std::make_shared(type) : nullptr; + return type ? std::make_shared(std::make_shared(type)) : nullptr; } -service::FieldResult> InputValue::getDefaultValue( - service::FieldParams&&) const +std::optional InputValue::getDefaultValue() const { const auto defaultValue = _inputValue->defaultValue(); - return { defaultValue.empty() ? std::nullopt - : std::make_optional(defaultValue) }; + return { defaultValue.empty() ? std::nullopt : std::make_optional(defaultValue) }; } EnumValue::EnumValue(const std::shared_ptr& enumValue) @@ -328,31 +342,28 @@ EnumValue::EnumValue(const std::shared_ptr& enumValue) { } -service::FieldResult EnumValue::getName(service::FieldParams&&) const +std::string EnumValue::getName() const { - return response::StringType { _enumValue->name() }; + return std::string { _enumValue->name() }; } -service::FieldResult> EnumValue::getDescription( - service::FieldParams&&) const +std::optional EnumValue::getDescription() const { const auto description = _enumValue->description(); - return { description.empty() ? std::nullopt - : std::make_optional(description) }; + return { description.empty() ? std::nullopt : std::make_optional(description) }; } -service::FieldResult EnumValue::getIsDeprecated(service::FieldParams&&) const +bool EnumValue::getIsDeprecated() const { return _enumValue->deprecationReason().has_value(); } -service::FieldResult> EnumValue::getDeprecationReason( - service::FieldParams&&) const +std::optional EnumValue::getDeprecationReason() const { const auto& deprecationReason = _enumValue->deprecationReason(); - return { deprecationReason ? std::make_optional(*deprecationReason) + return { deprecationReason ? std::make_optional(*deprecationReason) : std::nullopt }; } @@ -361,37 +372,38 @@ Directive::Directive(const std::shared_ptr& directive) { } -service::FieldResult Directive::getName(service::FieldParams&&) const +std::string Directive::getName() const { - return response::StringType { _directive->name() }; + return std::string { _directive->name() }; } -service::FieldResult> Directive::getDescription( - service::FieldParams&&) const +std::optional Directive::getDescription() const { const auto description = _directive->description(); - return { description.empty() ? std::nullopt - : std::make_optional(description) }; + return { description.empty() ? std::nullopt : std::make_optional(description) }; } -service::FieldResult> Directive::getLocations( - service::FieldParams&&) const +std::vector Directive::getLocations() const { - return { _directive->locations() }; + return _directive->locations(); } -service::FieldResult>> Directive::getArgs( - service::FieldParams&&) const +std::vector> Directive::getArgs() const { const auto& args = _directive->args(); std::vector> result(args.size()); std::transform(args.begin(), args.end(), result.begin(), [](const auto& entry) { - return std::make_shared(entry); + return std::make_shared(std::make_shared(entry)); }); return result; } +bool Directive::getIsRepeatable() const +{ + return _directive->isRepeatable(); +} + } // namespace graphql::introspection diff --git a/src/IntrospectionSchema.cpp b/src/IntrospectionSchema.cpp deleted file mode 100644 index 41a15207..00000000 --- a/src/IntrospectionSchema.cpp +++ /dev/null @@ -1,718 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// WARNING! Do not edit this file manually, your changes will be overwritten. - -#include "graphqlservice/introspection/Introspection.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std::literals; - -namespace graphql { -namespace service { - -static const std::array s_namesTypeKind = { - "SCALAR"sv, - "OBJECT"sv, - "INTERFACE"sv, - "UNION"sv, - "ENUM"sv, - "INPUT_OBJECT"sv, - "LIST"sv, - "NON_NULL"sv -}; - -template <> -introspection::TypeKind ModifiedArgument::convert(const response::Value& value) -{ - if (!value.maybe_enum()) - { - throw service::schema_exception { { "not a valid __TypeKind value" } }; - } - - const auto itr = std::find(s_namesTypeKind.cbegin(), s_namesTypeKind.cend(), value.get()); - - if (itr == s_namesTypeKind.cend()) - { - throw service::schema_exception { { "not a valid __TypeKind value" } }; - } - - return static_cast(itr - s_namesTypeKind.cbegin()); -} - -template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) -{ - return resolve(std::move(result), std::move(params), - [](introspection::TypeKind value, const ResolverParams&) - { - response::Value result(response::Type::EnumValue); - - result.set(response::StringType { s_namesTypeKind[static_cast(value)] }); - - return result; - }); -} - -static const std::array s_namesDirectiveLocation = { - "QUERY"sv, - "MUTATION"sv, - "SUBSCRIPTION"sv, - "FIELD"sv, - "FRAGMENT_DEFINITION"sv, - "FRAGMENT_SPREAD"sv, - "INLINE_FRAGMENT"sv, - "SCHEMA"sv, - "SCALAR"sv, - "OBJECT"sv, - "FIELD_DEFINITION"sv, - "ARGUMENT_DEFINITION"sv, - "INTERFACE"sv, - "UNION"sv, - "ENUM"sv, - "ENUM_VALUE"sv, - "INPUT_OBJECT"sv, - "INPUT_FIELD_DEFINITION"sv -}; - -template <> -introspection::DirectiveLocation ModifiedArgument::convert(const response::Value& value) -{ - if (!value.maybe_enum()) - { - throw service::schema_exception { { "not a valid __DirectiveLocation value" } }; - } - - const auto itr = std::find(s_namesDirectiveLocation.cbegin(), s_namesDirectiveLocation.cend(), value.get()); - - if (itr == s_namesDirectiveLocation.cend()) - { - throw service::schema_exception { { "not a valid __DirectiveLocation value" } }; - } - - return static_cast(itr - s_namesDirectiveLocation.cbegin()); -} - -template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) -{ - return resolve(std::move(result), std::move(params), - [](introspection::DirectiveLocation value, const ResolverParams&) - { - response::Value result(response::Type::EnumValue); - - result.set(response::StringType { s_namesDirectiveLocation[static_cast(value)] }); - - return result; - }); -} - -} // namespace service - -namespace introspection { -namespace object { - -Schema::Schema() - : service::Object({ - "__Schema" - }, { - { R"gql(types)gql"sv, [this](service::ResolverParams&& params) { return resolveTypes(std::move(params)); } }, - { R"gql(queryType)gql"sv, [this](service::ResolverParams&& params) { return resolveQueryType(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(directives)gql"sv, [this](service::ResolverParams&& params) { return resolveDirectives(std::move(params)); } }, - { R"gql(mutationType)gql"sv, [this](service::ResolverParams&& params) { return resolveMutationType(std::move(params)); } }, - { R"gql(subscriptionType)gql"sv, [this](service::ResolverParams&& params) { return resolveSubscriptionType(std::move(params)); } } - }) -{ -} - -std::future Schema::resolveTypes(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getTypes(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Schema::resolveQueryType(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getQueryType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Schema::resolveMutationType(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getMutationType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Schema::resolveSubscriptionType(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getSubscriptionType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Schema::resolveDirectives(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDirectives(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Schema::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(__Schema)gql" }, std::move(params)); -} - -Type::Type() - : service::Object({ - "__Type" - }, { - { R"gql(kind)gql"sv, [this](service::ResolverParams&& params) { return resolveKind(std::move(params)); } }, - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(fields)gql"sv, [this](service::ResolverParams&& params) { return resolveFields(std::move(params)); } }, - { R"gql(ofType)gql"sv, [this](service::ResolverParams&& params) { return resolveOfType(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(enumValues)gql"sv, [this](service::ResolverParams&& params) { return resolveEnumValues(std::move(params)); } }, - { R"gql(interfaces)gql"sv, [this](service::ResolverParams&& params) { return resolveInterfaces(std::move(params)); } }, - { R"gql(description)gql"sv, [this](service::ResolverParams&& params) { return resolveDescription(std::move(params)); } }, - { R"gql(inputFields)gql"sv, [this](service::ResolverParams&& params) { return resolveInputFields(std::move(params)); } }, - { R"gql(possibleTypes)gql"sv, [this](service::ResolverParams&& params) { return resolvePossibleTypes(std::move(params)); } } - }) -{ -} - -std::future Type::resolveKind(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getKind(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Type::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Type::resolveDescription(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDescription(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Type::resolveFields(service::ResolverParams&& params) -{ - const auto defaultArguments = []() - { - response::Value values(response::Type::Map); - response::Value entry; - - entry = response::Value(false); - values.emplace_back("includeDeprecated", std::move(entry)); - - return values; - }(); - - auto pairIncludeDeprecated = service::ModifiedArgument::find("includeDeprecated", params.arguments); - auto argIncludeDeprecated = (pairIncludeDeprecated.second - ? std::move(pairIncludeDeprecated.first) - : service::ModifiedArgument::require("includeDeprecated", defaultArguments)); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getFields(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIncludeDeprecated)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Type::resolveInterfaces(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getInterfaces(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Type::resolvePossibleTypes(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getPossibleTypes(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Type::resolveEnumValues(service::ResolverParams&& params) -{ - const auto defaultArguments = []() - { - response::Value values(response::Type::Map); - response::Value entry; - - entry = response::Value(false); - values.emplace_back("includeDeprecated", std::move(entry)); - - return values; - }(); - - auto pairIncludeDeprecated = service::ModifiedArgument::find("includeDeprecated", params.arguments); - auto argIncludeDeprecated = (pairIncludeDeprecated.second - ? std::move(pairIncludeDeprecated.first) - : service::ModifiedArgument::require("includeDeprecated", defaultArguments)); - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getEnumValues(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)), std::move(argIncludeDeprecated)); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Type::resolveInputFields(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getInputFields(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Type::resolveOfType(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getOfType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Type::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(__Type)gql" }, std::move(params)); -} - -Field::Field() - : service::Object({ - "__Field" - }, { - { R"gql(args)gql"sv, [this](service::ResolverParams&& params) { return resolveArgs(std::move(params)); } }, - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(type)gql"sv, [this](service::ResolverParams&& params) { return resolveType(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(description)gql"sv, [this](service::ResolverParams&& params) { return resolveDescription(std::move(params)); } }, - { R"gql(isDeprecated)gql"sv, [this](service::ResolverParams&& params) { return resolveIsDeprecated(std::move(params)); } }, - { R"gql(deprecationReason)gql"sv, [this](service::ResolverParams&& params) { return resolveDeprecationReason(std::move(params)); } } - }) -{ -} - -std::future Field::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Field::resolveDescription(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDescription(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Field::resolveArgs(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getArgs(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Field::resolveType(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Field::resolveIsDeprecated(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getIsDeprecated(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Field::resolveDeprecationReason(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDeprecationReason(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Field::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(__Field)gql" }, std::move(params)); -} - -InputValue::InputValue() - : service::Object({ - "__InputValue" - }, { - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(type)gql"sv, [this](service::ResolverParams&& params) { return resolveType(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(description)gql"sv, [this](service::ResolverParams&& params) { return resolveDescription(std::move(params)); } }, - { R"gql(defaultValue)gql"sv, [this](service::ResolverParams&& params) { return resolveDefaultValue(std::move(params)); } } - }) -{ -} - -std::future InputValue::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future InputValue::resolveDescription(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDescription(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future InputValue::resolveType(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getType(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future InputValue::resolveDefaultValue(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDefaultValue(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future InputValue::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(__InputValue)gql" }, std::move(params)); -} - -EnumValue::EnumValue() - : service::Object({ - "__EnumValue" - }, { - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(description)gql"sv, [this](service::ResolverParams&& params) { return resolveDescription(std::move(params)); } }, - { R"gql(isDeprecated)gql"sv, [this](service::ResolverParams&& params) { return resolveIsDeprecated(std::move(params)); } }, - { R"gql(deprecationReason)gql"sv, [this](service::ResolverParams&& params) { return resolveDeprecationReason(std::move(params)); } } - }) -{ -} - -std::future EnumValue::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future EnumValue::resolveDescription(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDescription(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future EnumValue::resolveIsDeprecated(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getIsDeprecated(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future EnumValue::resolveDeprecationReason(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDeprecationReason(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future EnumValue::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(__EnumValue)gql" }, std::move(params)); -} - -Directive::Directive() - : service::Object({ - "__Directive" - }, { - { R"gql(args)gql"sv, [this](service::ResolverParams&& params) { return resolveArgs(std::move(params)); } }, - { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, - { R"gql(locations)gql"sv, [this](service::ResolverParams&& params) { return resolveLocations(std::move(params)); } }, - { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, - { R"gql(description)gql"sv, [this](service::ResolverParams&& params) { return resolveDescription(std::move(params)); } } - }) -{ -} - -std::future Directive::resolveName(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getName(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Directive::resolveDescription(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getDescription(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Directive::resolveLocations(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getLocations(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Directive::resolveArgs(service::ResolverParams&& params) -{ - std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = getArgs(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives))); - resolverLock.unlock(); - - return service::ModifiedResult::convert(std::move(result), std::move(params)); -} - -std::future Directive::resolve_typename(service::ResolverParams&& params) -{ - return service::ModifiedResult::convert(response::StringType{ R"gql(__Directive)gql" }, std::move(params)); -} - -} // namespace object - -void AddTypesToSchema(const std::shared_ptr& schema) -{ - schema->AddType(R"gql(Boolean)gql"sv, schema::ScalarType::Make(R"gql(Boolean)gql"sv, R"md(Built-in type)md")); - schema->AddType(R"gql(Float)gql"sv, schema::ScalarType::Make(R"gql(Float)gql"sv, R"md(Built-in type)md")); - schema->AddType(R"gql(ID)gql"sv, schema::ScalarType::Make(R"gql(ID)gql"sv, R"md(Built-in type)md")); - schema->AddType(R"gql(Int)gql"sv, schema::ScalarType::Make(R"gql(Int)gql"sv, R"md(Built-in type)md")); - schema->AddType(R"gql(String)gql"sv, schema::ScalarType::Make(R"gql(String)gql"sv, R"md(Built-in type)md")); - auto typeTypeKind = schema::EnumType::Make(R"gql(__TypeKind)gql"sv, R"md()md"sv); - schema->AddType(R"gql(__TypeKind)gql"sv, typeTypeKind); - auto typeDirectiveLocation = schema::EnumType::Make(R"gql(__DirectiveLocation)gql"sv, R"md()md"sv); - schema->AddType(R"gql(__DirectiveLocation)gql"sv, typeDirectiveLocation); - auto typeSchema = schema::ObjectType::Make(R"gql(__Schema)gql"sv, R"md()md"); - schema->AddType(R"gql(__Schema)gql"sv, typeSchema); - auto typeType = schema::ObjectType::Make(R"gql(__Type)gql"sv, R"md()md"); - schema->AddType(R"gql(__Type)gql"sv, typeType); - auto typeField = schema::ObjectType::Make(R"gql(__Field)gql"sv, R"md()md"); - schema->AddType(R"gql(__Field)gql"sv, typeField); - auto typeInputValue = schema::ObjectType::Make(R"gql(__InputValue)gql"sv, R"md()md"); - schema->AddType(R"gql(__InputValue)gql"sv, typeInputValue); - auto typeEnumValue = schema::ObjectType::Make(R"gql(__EnumValue)gql"sv, R"md()md"); - schema->AddType(R"gql(__EnumValue)gql"sv, typeEnumValue); - auto typeDirective = schema::ObjectType::Make(R"gql(__Directive)gql"sv, R"md()md"); - schema->AddType(R"gql(__Directive)gql"sv, typeDirective); - - typeTypeKind->AddEnumValues({ - { service::s_namesTypeKind[static_cast(introspection::TypeKind::SCALAR)], R"md()md"sv, std::nullopt }, - { service::s_namesTypeKind[static_cast(introspection::TypeKind::OBJECT)], R"md()md"sv, std::nullopt }, - { service::s_namesTypeKind[static_cast(introspection::TypeKind::INTERFACE)], R"md()md"sv, std::nullopt }, - { service::s_namesTypeKind[static_cast(introspection::TypeKind::UNION)], R"md()md"sv, std::nullopt }, - { service::s_namesTypeKind[static_cast(introspection::TypeKind::ENUM)], R"md()md"sv, std::nullopt }, - { service::s_namesTypeKind[static_cast(introspection::TypeKind::INPUT_OBJECT)], R"md()md"sv, std::nullopt }, - { service::s_namesTypeKind[static_cast(introspection::TypeKind::LIST)], R"md()md"sv, std::nullopt }, - { service::s_namesTypeKind[static_cast(introspection::TypeKind::NON_NULL)], R"md()md"sv, std::nullopt } - }); - typeDirectiveLocation->AddEnumValues({ - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::QUERY)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::MUTATION)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SUBSCRIPTION)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FIELD)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FRAGMENT_DEFINITION)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FRAGMENT_SPREAD)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INLINE_FRAGMENT)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SCHEMA)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SCALAR)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::OBJECT)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FIELD_DEFINITION)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ARGUMENT_DEFINITION)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INTERFACE)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::UNION)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ENUM)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ENUM_VALUE)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INPUT_OBJECT)], R"md()md"sv, std::nullopt }, - { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INPUT_FIELD_DEFINITION)], R"md()md"sv, std::nullopt } - }); - - typeSchema->AddFields({ - schema::Field::Make(R"gql(types)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))))), - schema::Field::Make(R"gql(queryType)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))), - schema::Field::Make(R"gql(mutationType)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("__Type")), - schema::Field::Make(R"gql(subscriptionType)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("__Type")), - schema::Field::Make(R"gql(directives)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Directive"))))) - }); - typeType->AddFields({ - schema::Field::Make(R"gql(kind)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__TypeKind"))), - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(fields)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Field"))), { - schema::InputValue::Make(R"gql(includeDeprecated)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(false)gql"sv) - }), - schema::Field::Make(R"gql(interfaces)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type")))), - schema::Field::Make(R"gql(possibleTypes)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type")))), - schema::Field::Make(R"gql(enumValues)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__EnumValue"))), { - schema::InputValue::Make(R"gql(includeDeprecated)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(false)gql"sv) - }), - schema::Field::Make(R"gql(inputFields)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__InputValue")))), - schema::Field::Make(R"gql(ofType)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("__Type")) - }); - typeField->AddFields({ - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(args)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__InputValue"))))), - schema::Field::Make(R"gql(type)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))), - schema::Field::Make(R"gql(isDeprecated)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - schema::Field::Make(R"gql(deprecationReason)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); - typeInputValue->AddFields({ - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(type)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))), - schema::Field::Make(R"gql(defaultValue)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); - typeEnumValue->AddFields({ - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(isDeprecated)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - schema::Field::Make(R"gql(deprecationReason)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) - }); - typeDirective->AddFields({ - schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), - schema::Field::Make(R"gql(locations)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__DirectiveLocation"))))), - schema::Field::Make(R"gql(args)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__InputValue"))))) - }); - - schema->AddDirective(schema::Directive::Make(R"gql(skip)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::FIELD, - introspection::DirectiveLocation::FRAGMENT_SPREAD, - introspection::DirectiveLocation::INLINE_FRAGMENT - }, { - schema::InputValue::Make(R"gql(if)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(include)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::FIELD, - introspection::DirectiveLocation::FRAGMENT_SPREAD, - introspection::DirectiveLocation::INLINE_FRAGMENT - }, { - schema::InputValue::Make(R"gql(if)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql()gql"sv) - })); - schema->AddDirective(schema::Directive::Make(R"gql(deprecated)gql"sv, R"md()md"sv, { - introspection::DirectiveLocation::FIELD_DEFINITION, - introspection::DirectiveLocation::ENUM_VALUE - }, { - schema::InputValue::Make(R"gql(reason)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql("No longer supported")gql"sv) - })); -} - -} // namespace introspection -} // namespace graphql diff --git a/src/JSONResponse.cpp b/src/JSONResponse.cpp index c0d9172d..cc5dbacb 100644 --- a/src/JSONResponse.cpp +++ b/src/JSONResponse.cpp @@ -16,94 +16,74 @@ namespace graphql::response { -void writeResponse(rapidjson::Writer& writer, Value&& response) +class StringWriter { - switch (response.type()) +public: + StringWriter(rapidjson::StringBuffer& buffer) + : _writer { buffer } { - case Type::Map: - { - auto members = response.release(); - - writer.StartObject(); - - for (auto& entry : members) - { - writer.Key(entry.first.c_str()); - writeResponse(writer, std::move(entry.second)); - } - - writer.EndObject(); - break; - } - - case Type::List: - { - auto elements = response.release(); - - writer.StartArray(); + } - for (auto& entry : elements) - { - writeResponse(writer, std::move(entry)); - } + void start_object() + { + _writer.StartObject(); + } - writer.EndArray(); - break; - } + void add_member(const std::string& key) + { + _writer.Key(key.c_str()); + } - case Type::String: - case Type::EnumValue: - { - auto value = response.release(); + void end_object() + { + _writer.EndObject(); + } - writer.String(value.c_str()); - break; - } + void start_array() + { + _writer.StartArray(); + } - case Type::Null: - { - writer.Null(); - break; - } + void end_arrary() + { + _writer.EndArray(); + } - case Type::Boolean: - { - writer.Bool(response.get()); - break; - } + void write_null() + { + _writer.Null(); + } - case Type::Int: - { - writer.Int(response.get()); - break; - } + void write_string(const std::string& value) + { + _writer.String(value.c_str()); + } - case Type::Float: - { - writer.Double(response.get()); - break; - } + void write_bool(bool value) + { + _writer.Bool(value); + } - case Type::Scalar: - { - writeResponse(writer, response.release()); - break; - } + void write_int(int value) + { + _writer.Int(value); + } - default: - { - writer.Null(); - break; - } + void write_float(double value) + { + _writer.Double(value); } -} + +private: + rapidjson::Writer _writer; +}; std::string toJSON(Value&& response) { rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); + Writer writer { std::make_unique(buffer) }; - writeResponse(writer, std::move(response)); + writer.write(std::move(response)); return buffer.GetString(); } @@ -138,7 +118,7 @@ struct ResponseHandler : rapidjson::BaseReaderHandler, Respons bool Int(int i) { - // http://spec.graphql.org/June2018/#sec-Int + // https://spec.graphql.org/October2021/#sec-Int static_assert(sizeof(i) == 4, "GraphQL only supports 32-bit signed integers"); auto value = Value(Type::Int); @@ -151,7 +131,7 @@ struct ResponseHandler : rapidjson::BaseReaderHandler, Respons { if (i > static_cast(std::numeric_limits::max())) { - // http://spec.graphql.org/June2018/#sec-Int + // https://spec.graphql.org/October2021/#sec-Int throw std::overflow_error("GraphQL only supports 32-bit signed integers"); } return Int(static_cast(i)); @@ -159,13 +139,13 @@ struct ResponseHandler : rapidjson::BaseReaderHandler, Respons bool Int64(int64_t /*i*/) { - // http://spec.graphql.org/June2018/#sec-Int + // https://spec.graphql.org/October2021/#sec-Int throw std::overflow_error("GraphQL only supports 32-bit signed integers"); } bool Uint64(uint64_t /*i*/) { - // http://spec.graphql.org/June2018/#sec-Int + // https://spec.graphql.org/October2021/#sec-Int throw std::overflow_error("GraphQL only supports 32-bit signed integers"); } diff --git a/src/RequestLoader.cpp b/src/RequestLoader.cpp index 73c7b902..3ef113d7 100644 --- a/src/RequestLoader.cpp +++ b/src/RequestLoader.cpp @@ -7,7 +7,7 @@ #include "graphqlservice/internal/Grammar.h" -#include "graphqlservice/introspection/Introspection.h" +#include "graphqlservice/introspection/IntrospectionSchema.h" #include #include @@ -276,7 +276,9 @@ void RequestLoader::addTypesToSchema() for (const auto& scalarType : _schemaLoader.getScalarTypes()) { _schema->AddType(scalarType.type, - schema::ScalarType::Make(scalarType.type, scalarType.description)); + schema::ScalarType::Make(scalarType.type, + scalarType.description, + scalarType.specifiedByURL)); } } @@ -520,7 +522,7 @@ void RequestLoader::addTypesToSchema() [](std::string_view locationName) noexcept { response::Value locationValue(response::Type::EnumValue); - locationValue.set(response::StringType { locationName }); + locationValue.set(std::string { locationName }); return service::ModifiedArgument::convert( locationValue); @@ -542,7 +544,8 @@ void RequestLoader::addTypesToSchema() _schema->AddDirective(schema::Directive::Make(directive.name, directive.description, std::move(locations), - std::move(arguments))); + std::move(arguments), + directive.isRepeatable)); } for (const auto& operationType : _schemaLoader.getOperationTypes()) diff --git a/src/Schema.cpp b/src/Schema.cpp index 4541cab4..efe070ac 100644 --- a/src/Schema.cpp +++ b/src/Schema.cpp @@ -9,8 +9,9 @@ using namespace std::literals; namespace graphql::schema { -Schema::Schema(bool noIntrospection) +Schema::Schema(bool noIntrospection, std::string_view description) : _noIntrospection(noIntrospection) + , _description(description) { } @@ -88,6 +89,11 @@ void Schema::AddDirective(std::shared_ptr directive) _directives.emplace_back(std::move(directive)); } +std::string_view Schema::description() const noexcept +{ + return _description; +} + const std::vector>>& Schema::types() const noexcept { @@ -171,20 +177,28 @@ const std::weak_ptr& BaseType::ofType() const noexcept return defaultValue; } +std::string_view BaseType::specifiedByURL() const noexcept +{ + return ""sv; +} + struct ScalarType::init { std::string_view name; std::string_view description; + std::string_view specifiedByURL; }; -std::shared_ptr ScalarType::Make(std::string_view name, std::string_view description) +std::shared_ptr ScalarType::Make( + std::string_view name, std::string_view description, std::string_view specifiedByURL) { - return std::make_shared(init { name, description }); + return std::make_shared(init { name, description, specifiedByURL }); } ScalarType::ScalarType(init&& params) : BaseType(introspection::TypeKind::SCALAR, params.description) , _name(params.name) + , _specifiedByURL(params.specifiedByURL) { } @@ -193,6 +207,11 @@ std::string_view ScalarType::name() const noexcept return _name; } +std::string_view ScalarType::specifiedByURL() const noexcept +{ + return _specifiedByURL; +} + struct ObjectType::init { std::string_view name; @@ -216,8 +235,7 @@ void ObjectType::AddInterfaces(std::vector> for (const auto& interface : _interfaces) { - std::const_pointer_cast(interface)->AddPossibleType( - std::static_pointer_cast(shared_from_this())); + std::const_pointer_cast(interface)->AddPossibleType(shared_from_this()); } } @@ -259,11 +277,21 @@ InterfaceType::InterfaceType(init&& params) { } -void InterfaceType::AddPossibleType(std::weak_ptr possibleType) +void InterfaceType::AddPossibleType(std::weak_ptr possibleType) { _possibleTypes.push_back(possibleType); } +void InterfaceType::AddInterfaces(std::vector>&& interfaces) +{ + _interfaces = std::move(interfaces); + + for (const auto& interface : _interfaces) + { + std::const_pointer_cast(interface)->AddPossibleType(shared_from_this()); + } +} + void InterfaceType::AddFields(std::vector>&& fields) { _fields = std::move(fields); @@ -284,6 +312,11 @@ const std::vector>& InterfaceType::possibleTypes() return _possibleTypes; } +const std::vector>& InterfaceType::interfaces() const noexcept +{ + return _interfaces; +} + struct UnionType::init { std::string_view name; @@ -545,13 +578,14 @@ struct Directive::init std::string_view description; std::vector locations; std::vector> args; + bool isRepeatable; }; std::shared_ptr Directive::Make(std::string_view name, std::string_view description, std::vector&& locations, - std::vector>&& args) + std::vector>&& args, bool isRepeatable) { - init params { name, description, std::move(locations), std::move(args) }; + init params { name, description, std::move(locations), std::move(args), isRepeatable }; return std::make_shared(std::move(params)); } @@ -561,6 +595,7 @@ Directive::Directive(init&& params) , _description(params.description) , _locations(std::move(params.locations)) , _args(std::move(params.args)) + , _isRepeatable(params.isRepeatable) { } @@ -584,4 +619,9 @@ const std::vector>& Directive::args() const no return _args; } +bool Directive::isRepeatable() const noexcept +{ + return _isRepeatable; +} + } // namespace graphql::schema diff --git a/src/SchemaGenerator.cpp b/src/SchemaGenerator.cpp index 6234a91e..4c0c72c0 100644 --- a/src/SchemaGenerator.cpp +++ b/src/SchemaGenerator.cpp @@ -16,52 +16,34 @@ #pragma warning(pop) #endif // _MSC_VER -// clang-format off -#ifdef USE_STD_FILESYSTEM - #include - namespace fs = std::filesystem; -#else - #ifdef USE_STD_EXPERIMENTAL_FILESYSTEM - #include - namespace fs = std::experimental::filesystem; - #else - #ifdef USE_BOOST_FILESYSTEM - #include - namespace fs = boost::filesystem; - #else - #error "No std::filesystem implementation defined" - #endif - #endif -#endif -// clang-format on - #include +#include #include #include #include #include #include +#include using namespace std::literals; namespace graphql::generator::schema { -Generator::Generator(std::optional&& customSchema, GeneratorOptions&& options) - : _loader(std::move(customSchema)) +Generator::Generator(SchemaOptions&& schemaOptions, GeneratorOptions&& options) + : _loader(std::move(schemaOptions)) , _options(std::move(options)) , _headerDir(getHeaderDir()) , _sourceDir(getSourceDir()) , _headerPath(getHeaderPath()) - , _objectHeaderPath(getObjectHeaderPath()) , _sourcePath(getSourcePath()) { } std::string Generator::getHeaderDir() const noexcept { - if (_options.paths) + if (!_options.paths.headerPath.empty()) { - return fs::path { _options.paths->headerPath }.string(); + return std::filesystem::path { _options.paths.headerPath }.string(); } else { @@ -71,9 +53,9 @@ std::string Generator::getHeaderDir() const noexcept std::string Generator::getSourceDir() const noexcept { - if (_options.paths) + if (!_options.paths.sourcePath.empty()) { - return fs::path(_options.paths->sourcePath).string(); + return std::filesystem::path(_options.paths.sourcePath).string(); } else { @@ -83,28 +65,15 @@ std::string Generator::getSourceDir() const noexcept std::string Generator::getHeaderPath() const noexcept { - fs::path fullPath { _headerDir }; + std::filesystem::path fullPath { _headerDir }; fullPath /= (std::string { _loader.getFilenamePrefix() } + "Schema.h"); return fullPath.string(); } -std::string Generator::getObjectHeaderPath() const noexcept -{ - if (_options.separateFiles) - { - fs::path fullPath { _headerDir }; - - fullPath /= (std::string { _loader.getFilenamePrefix() } + "Objects.h"); - return fullPath.string(); - } - - return _headerPath; -} - std::string Generator::getSourcePath() const noexcept { - fs::path fullPath { _sourceDir }; + std::filesystem::path fullPath { _sourceDir }; fullPath /= (std::string { _loader.getFilenamePrefix() } + "Schema.cpp"); return fullPath.string(); @@ -124,14 +93,11 @@ std::vector Generator::Build() const noexcept builtFiles.push_back(_sourcePath); } - if (_options.separateFiles) - { - auto separateFiles = outputSeparateFiles(); + auto separateFiles = outputSeparateFiles(); - for (auto& file : separateFiles) - { - builtFiles.push_back(std::move(file)); - } + for (auto& file : separateFiles) + { + builtFiles.push_back(std::move(file)); } return builtFiles; @@ -140,7 +106,8 @@ std::vector Generator::Build() const noexcept bool Generator::outputHeader() const noexcept { std::ofstream headerFile(_headerPath, std::ios_base::trunc); - IncludeGuardScope includeGuard { headerFile, fs::path(_headerPath).filename().string() }; + IncludeGuardScope includeGuard { headerFile, + std::filesystem::path(_headerPath).filename().string() }; headerFile << R"cpp(#include "graphqlservice/internal/Schema.h" @@ -241,7 +208,7 @@ static_assert(graphql::internal::MinorVersion == )cpp" )cpp"; for (const auto& inputField : inputType.fields) { - headerFile << R"cpp( )cpp" << getFieldDeclaration(inputField) << R"cpp(; + headerFile << getFieldDeclaration(inputField) << R"cpp( {}; )cpp"; } headerFile << R"cpp(}; @@ -250,71 +217,70 @@ static_assert(graphql::internal::MinorVersion == )cpp" } } - if (!_loader.getObjectTypes().empty()) + if (!_loader.getInterfaceTypes().empty()) { objectNamespace.enter(); headerFile << std::endl; - // Forward declare all of the object types - for (const auto& objectType : _loader.getObjectTypes()) + // Forward declare all of the interface types + for (const auto& interfaceType : _loader.getInterfaceTypes()) { - headerFile << R"cpp(class )cpp" << objectType.cppType << R"cpp(; + headerFile << R"cpp(class )cpp" << interfaceType.cppType << R"cpp(; )cpp"; } headerFile << std::endl; } - if (!_loader.getInterfaceTypes().empty()) + if (!_loader.getUnionTypes().empty()) { - if (objectNamespace.exit()) + if (objectNamespace.enter()) { headerFile << std::endl; } - // Forward declare all of the interface types - if (_loader.getInterfaceTypes().size() > 1) + // Forward declare all of the union types + for (const auto& unionType : _loader.getUnionTypes()) { - for (const auto& interfaceType : _loader.getInterfaceTypes()) - { - headerFile << R"cpp(struct )cpp" << interfaceType.cppType << R"cpp(; + headerFile << R"cpp(class )cpp" << unionType.cppType << R"cpp(; )cpp"; - } - - headerFile << std::endl; } - // Output the full declarations - for (const auto& interfaceType : _loader.getInterfaceTypes()) - { - headerFile << R"cpp(struct )cpp" << interfaceType.cppType << R"cpp( -{ -)cpp"; + headerFile << std::endl; + } - for (const auto& outputField : interfaceType.fields) + if (!_loader.getObjectTypes().empty()) + { + if (_loader.isIntrospection()) + { + if (objectNamespace.exit()) { - headerFile << getFieldDeclaration(outputField); + headerFile << std::endl; } - headerFile << R"cpp(}; - + // Forward declare all of the concrete types for the Introspection schema + for (const auto& objectType : _loader.getObjectTypes()) + { + headerFile << R"cpp(class )cpp" << objectType.cppType << R"cpp(; )cpp"; + } + + headerFile << std::endl; } - } - if (!_loader.getObjectTypes().empty() && !_options.separateFiles) - { if (objectNamespace.enter()) { headerFile << std::endl; } - // Output the full declarations + // Forward declare all of the object types for (const auto& objectType : _loader.getObjectTypes()) { - outputObjectDeclaration(headerFile, objectType, objectType.type == queryType); - headerFile << std::endl; + headerFile << R"cpp(class )cpp" << objectType.cppType << R"cpp(; +)cpp"; } + + headerFile << std::endl; } if (objectNamespace.exit()) @@ -345,7 +311,66 @@ static_assert(graphql::internal::MinorVersion == )cpp" } headerFile << R"cpp(); +)cpp"; + + if (!_loader.getOperationTypes().empty()) + { + firstOperation = true; + + headerFile << R"cpp( + template <)cpp"; + for (const auto& operation : _loader.getOperationTypes()) + { + if (!firstOperation) + { + headerFile << R"cpp(, )cpp"; + } + + firstOperation = false; + headerFile << R"cpp(class T)cpp" << operation.cppType; + } + + headerFile << R"cpp(> + explicit Operations()cpp"; + + firstOperation = true; + + for (const auto& operation : _loader.getOperationTypes()) + { + if (!firstOperation) + { + headerFile << R"cpp(, )cpp"; + } + + firstOperation = false; + headerFile << R"cpp(std::shared_ptr )cpp" + << operation.operation; + } + + headerFile << R"cpp() + : Operations {)cpp"; + firstOperation = true; + + for (const auto& operation : _loader.getOperationTypes()) + { + if (!firstOperation) + { + headerFile << R"cpp(,)cpp"; + } + + firstOperation = false; + headerFile << R"cpp( std::make_shared(std::move()cpp" << operation.operation << R"cpp()))cpp"; + } + + headerFile << R"cpp( } + { + } +)cpp"; + } + + headerFile << R"cpp( private: )cpp"; @@ -361,12 +386,40 @@ static_assert(graphql::internal::MinorVersion == )cpp" )cpp"; } - if (!_loader.getObjectTypes().empty() && _options.separateFiles) + if (!_loader.getInterfaceTypes().empty()) + { + for (const auto& interfaceType : _loader.getInterfaceTypes()) + { + headerFile << R"cpp(void Add)cpp" << interfaceType.cppType + << R"cpp(Details(const std::shared_ptr& type)cpp" + << interfaceType.cppType + << R"cpp(, const std::shared_ptr& schema); +)cpp"; + } + + headerFile << std::endl; + } + + if (!_loader.getUnionTypes().empty()) + { + for (const auto& unionType : _loader.getUnionTypes()) + { + headerFile << R"cpp(void Add)cpp" << unionType.cppType + << R"cpp(Details(const std::shared_ptr& type)cpp" + << unionType.cppType + << R"cpp(, const std::shared_ptr& schema); +)cpp"; + } + + headerFile << std::endl; + } + + if (!_loader.getObjectTypes().empty()) { for (const auto& objectType : _loader.getObjectTypes()) { headerFile << R"cpp(void Add)cpp" << objectType.cppType - << R"cpp(Details(std::shared_ptr type)cpp" + << R"cpp(Details(const std::shared_ptr& type)cpp" << objectType.cppType << R"cpp(, const std::shared_ptr& schema); )cpp"; @@ -405,12 +458,17 @@ GRAPHQLINTROSPECTION_EXPORT )cpp" << R"cpp(::)cpp" << enumType.cppType << R"cpp(>::convert( const response::Value& value); template <> -GRAPHQLINTROSPECTION_EXPORT std::future ModifiedResult<)cpp" +GRAPHQLINTROSPECTION_EXPORT AwaitableResolver ModifiedResult<)cpp" << _loader.getSchemaNamespace() << R"cpp(::)cpp" << enumType.cppType << R"cpp(>::convert( - FieldResult<)cpp" << _loader.getSchemaNamespace() + AwaitableScalar<)cpp" << _loader.getSchemaNamespace() << R"cpp(::)cpp" << enumType.cppType - << R"cpp(>&& result, ResolverParams&& params); + << R"cpp(> result, ResolverParams params); +template <> +GRAPHQLINTROSPECTION_EXPORT void ModifiedResult<)cpp" + << _loader.getSchemaNamespace() << R"cpp(::)cpp" << enumType.cppType + << R"cpp(>::validateScalar( + const response::Value& value); )cpp"; } @@ -440,80 +498,518 @@ GRAPHQLINTROSPECTION_EXPORT )cpp" return true; } +void Generator::outputInterfaceDeclaration(std::ostream& headerFile, std::string_view cppType) const +{ + headerFile + << R"cpp(class )cpp" << cppType << R"cpp( + : public service::Object +{ +private: + struct Concept + { + virtual ~Concept() = default; + + virtual service::TypeNames getTypeNames() const noexcept = 0; + virtual service::ResolverMap getResolvers() const noexcept = 0; + + virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::TypeNames getTypeNames() const noexcept final + { + return _pimpl->getTypeNames(); + } + + service::ResolverMap getResolvers() const noexcept final + { + return _pimpl->getResolvers(); + } + + void beginSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->beginSelectionSet(params); + } + + void endSelectionSet(const service::SelectionSetParams& params) const final + { + _pimpl->endSelectionSet(params); + } + + private: + const std::shared_ptr _pimpl; + }; + + )cpp" + << cppType << R"cpp((std::unique_ptr&& pimpl) noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + )cpp" + << cppType << R"cpp((std::shared_ptr pimpl) noexcept + : )cpp" + << cppType + << R"cpp( { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + static_assert(T::template implements<)cpp" + << cppType << R"cpp(>(), ")cpp" << cppType << R"cpp( is not implemented"); + } +}; +)cpp"; +} + +void Generator::outputObjectImplements(std::ostream& headerFile, const ObjectType& objectType) const +{ + headerFile << R"cpp(template +concept )cpp" << objectType.cppType + << R"cpp(Is = )cpp"; + + bool firstInterface = true; + + for (auto interfaceName : objectType.interfaces) + { + if (!firstInterface) + { + headerFile << R"cpp( || )cpp"; + } + + headerFile << R"cpp(std::is_same_v)cpp"; + firstInterface = false; + } + + for (auto unionName : objectType.unions) + { + if (!firstInterface) + { + headerFile << R"cpp( || )cpp"; + } + + headerFile << R"cpp(std::is_same_v)cpp"; + firstInterface = false; + } + + headerFile << R"cpp(; + +)cpp"; +} + +void Generator::outputObjectStubs(std::ostream& headerFile, const ObjectType& objectType) const +{ + for (const auto& outputField : objectType.fields) + { + std::string fieldName(outputField.cppName); + + fieldName[0] = static_cast(std::toupper(static_cast(fieldName[0]))); + + std::ostringstream ossPassedArguments; + bool firstArgument = true; + + for (const auto& argument : outputField.arguments) + { + if (!firstArgument) + { + ossPassedArguments << R"cpp(, )cpp"; + } + + ossPassedArguments << R"cpp(std::move()cpp" << argument.cppName << R"cpp(Arg))cpp"; + firstArgument = false; + } + + const auto passedArguments = ossPassedArguments.str(); + + headerFile << R"cpp( +template +concept )cpp" << outputField.accessor + << fieldName + << R"cpp(WithParams = requires (TImpl impl, service::FieldParams params)cpp"; + for (const auto& argument : outputField.arguments) + { + headerFile << R"cpp(, )cpp" << _loader.getInputCppType(argument) << R"cpp( )cpp" + << argument.cppName << R"cpp(Arg)cpp"; + } + + headerFile << R"cpp() +{ + { )cpp" << _loader.getOutputCppType(outputField) + << R"cpp( { impl.)cpp" << outputField.accessor << fieldName + << R"cpp((std::move(params))cpp"; + + if (!passedArguments.empty()) + { + headerFile << R"cpp(, )cpp" << passedArguments; + } + + headerFile << R"cpp() } }; +}; + +template +concept )cpp" << outputField.accessor + << fieldName << R"cpp( = requires (TImpl impl)cpp"; + for (const auto& argument : outputField.arguments) + { + headerFile << R"cpp(, )cpp" << _loader.getInputCppType(argument) << R"cpp( )cpp" + << argument.cppName << R"cpp(Arg)cpp"; + } + + headerFile << R"cpp() +{ + { )cpp" << _loader.getOutputCppType(outputField) + << R"cpp( { impl.)cpp" << outputField.accessor << fieldName << R"cpp(()cpp"; + + if (!passedArguments.empty()) + { + headerFile << passedArguments; + } + + headerFile << R"cpp() } }; +}; +)cpp"; + } + + headerFile << R"cpp( +template +concept beginSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.beginSelectionSet(params) }; +}; + +template +concept endSelectionSet = requires (TImpl impl, const service::SelectionSetParams params) +{ + { impl.endSelectionSet(params) }; +}; + +)cpp"; +} + void Generator::outputObjectDeclaration( std::ostream& headerFile, const ObjectType& objectType, bool isQueryType) const { headerFile << R"cpp(class )cpp" << objectType.cppType << R"cpp( - : public service::Object)cpp"; + : public service::Object +{ +private: +)cpp"; - for (const auto& interfaceName : objectType.interfaces) + for (const auto& outputField : objectType.fields) { - headerFile << R"cpp( - , public )cpp" << _loader.getSafeCppName(interfaceName); + headerFile << getResolverDeclaration(outputField); } headerFile << R"cpp( -{ -protected: - explicit )cpp" - << objectType.cppType << R"cpp((); + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; )cpp"; - if (!objectType.fields.empty()) + if (!_options.noIntrospection && isQueryType) { - bool firstField = true; + headerFile + << R"cpp( service::AwaitableResolver resolve_schema(service::ResolverParams&& params) const; + service::AwaitableResolver resolve_type(service::ResolverParams&& params) const; + + std::shared_ptr _schema; +)cpp"; + } - for (const auto& outputField : objectType.fields) + headerFile << R"cpp( + struct Concept + { + virtual ~Concept() = default; + +)cpp"; + + if (!_loader.isIntrospection()) + { + headerFile + << R"cpp( virtual void beginSelectionSet(const service::SelectionSetParams& params) const = 0; + virtual void endSelectionSet(const service::SelectionSetParams& params) const = 0; + +)cpp"; + } + + for (const auto& outputField : objectType.fields) + { + headerFile << getFieldDeclaration(outputField); + } + + headerFile << R"cpp( }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } { - if (outputField.inheritedField && (_loader.isIntrospection() || _options.noStubs)) + } +)cpp"; + + for (const auto& outputField : objectType.fields) + { + std::string fieldName(outputField.cppName); + + fieldName[0] = static_cast(std::toupper(static_cast(fieldName[0]))); + + headerFile << R"cpp( + )cpp" << _loader.getOutputCppType(outputField) + << R"cpp( )cpp" << outputField.accessor << fieldName << R"cpp(()cpp"; + + bool firstArgument = _loader.isIntrospection(); + + if (!firstArgument) + { + headerFile << R"cpp(service::FieldParams&& params)cpp"; + } + + for (const auto& argument : outputField.arguments) + { + if (!firstArgument) { - continue; + headerFile << R"cpp(, )cpp"; } - if (firstField) + headerFile << _loader.getInputCppType(argument) << R"cpp(&& )cpp" << argument.cppName + << R"cpp(Arg)cpp"; + firstArgument = false; + } + + headerFile << R"cpp() const final + { + )cpp"; + + std::ostringstream ossPassedArguments; + firstArgument = true; + + for (const auto& argument : outputField.arguments) + { + if (!firstArgument) + { + ossPassedArguments << R"cpp(, )cpp"; + } + + ossPassedArguments << R"cpp(std::move()cpp" << argument.cppName << R"cpp(Arg))cpp"; + firstArgument = false; + } + + const auto passedArguments = ossPassedArguments.str(); + + if (_loader.isIntrospection()) + { + headerFile << R"cpp(return { _pimpl->)cpp" << outputField.accessor << fieldName + << R"cpp(()cpp"; + + if (!passedArguments.empty()) + { + headerFile << passedArguments; + } + + headerFile << R"cpp() };)cpp"; + } + else + { + headerFile << R"cpp(if constexpr (methods::)cpp" << objectType.cppType + << R"cpp(Has::)cpp" << outputField.accessor << fieldName + << R"cpp(WithParams) + { + return { _pimpl->)cpp" + << outputField.accessor << fieldName << R"cpp((std::move(params))cpp"; + + if (!passedArguments.empty()) + { + headerFile << R"cpp(, )cpp" << passedArguments; + } + + headerFile << R"cpp() }; + } + else)cpp"; + + if (!_options.stubs) { headerFile << R"cpp( -public: -)cpp"; - firstField = false; + { + static_assert(methods::)cpp" + << objectType.cppType << R"cpp(Has::)cpp" << outputField.accessor + << fieldName << R"cpp(, R"msg()cpp" << objectType.cppType + << R"cpp(::)cpp" << outputField.accessor << fieldName + << R"cpp( is not implemented)msg");)cpp"; + } + else + { + headerFile << R"cpp( if constexpr (methods::)cpp" << objectType.cppType + << R"cpp(Has::)cpp" << outputField.accessor << fieldName << R"cpp() + {)cpp"; } - headerFile << getFieldDeclaration(outputField); + headerFile << R"cpp( + return { _pimpl->)cpp" + << outputField.accessor << fieldName << R"cpp(()cpp"; + + if (!passedArguments.empty()) + { + headerFile << passedArguments; + } + + headerFile << R"cpp() }; + })cpp"; + + if (_options.stubs) + { + headerFile << R"cpp( + else + { + throw std::runtime_error(R"ex()cpp" + << objectType.cppType << R"cpp(::)cpp" << outputField.accessor + << fieldName << R"cpp( is not implemented)ex"); + })cpp"; + } } headerFile << R"cpp( -private: + } )cpp"; + } - for (const auto& outputField : objectType.fields) + if (!_loader.isIntrospection()) + { + headerFile << R"cpp( + void beginSelectionSet(const service::SelectionSetParams& params) const final { - headerFile << getResolverDeclaration(outputField); + if constexpr (methods::)cpp" + << objectType.cppType << R"cpp(Has::beginSelectionSet) + { + _pimpl->beginSelectionSet(params); + } } - headerFile << R"cpp( - std::future resolve_typename(service::ResolverParams&& params); + void endSelectionSet(const service::SelectionSetParams& params) const final + { + if constexpr (methods::)cpp" + << objectType.cppType << R"cpp(Has::endSelectionSet) + { + _pimpl->endSelectionSet(params); + } + } )cpp"; + } + + headerFile << R"cpp( + private: + const std::shared_ptr _pimpl; + }; + +)cpp"; + + if (_loader.isIntrospection()) + { + headerFile << R"cpp( const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; - if (!_options.noIntrospection && isQueryType) +public: + GRAPHQLINTROSPECTION_EXPORT )cpp" + << objectType.cppType << R"cpp((std::shared_ptr<)cpp" + << SchemaLoader::getIntrospectionNamespace() << R"cpp(::)cpp" + << objectType.cppType << R"cpp(> pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~)cpp" + << objectType.cppType << R"cpp((); +}; +)cpp"; + } + else + { + headerFile << R"cpp( )cpp" << objectType.cppType + << R"cpp((std::unique_ptr&& pimpl) noexcept; + +)cpp"; + + if (!objectType.interfaces.empty()) { - headerFile - << R"cpp( std::future resolve_schema(service::ResolverParams&& params); - std::future resolve_type(service::ResolverParams&& params); + headerFile << R"cpp( // Interfaces which this type implements +)cpp"; - std::shared_ptr _schema; + for (auto interfaceName : objectType.interfaces) + { + headerFile << R"cpp( friend )cpp" << _loader.getSafeCppName(interfaceName) + << R"cpp(; )cpp"; + } + + headerFile << std::endl; + } + + if (!objectType.unions.empty()) + { + headerFile << R"cpp( // Unions which include this type +)cpp"; + + for (auto unionName : objectType.unions) + { + headerFile << R"cpp( friend )cpp" << _loader.getSafeCppName(unionName) + << R"cpp(; +)cpp"; + } + + headerFile << std::endl; } + + if (!objectType.interfaces.empty() || !objectType.unions.empty()) + { + + headerFile << R"cpp( template + static constexpr bool implements() noexcept + { + return implements::)cpp" + << objectType.cppType << R"cpp(Is; } - headerFile << R"cpp(}; )cpp"; + } + + headerFile + << R"cpp( service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + + void beginSelectionSet(const service::SelectionSetParams& params) const final; + void endSelectionSet(const service::SelectionSetParams& params) const final; + + const std::unique_ptr _pimpl; + +public: + template + )cpp" << objectType.cppType + << R"cpp((std::shared_ptr pimpl) noexcept + : )cpp" + << objectType.cppType + << R"cpp( { std::unique_ptr { std::make_unique>(std::move(pimpl)) } } + { + } +}; +)cpp"; + } } std::string Generator::getFieldDeclaration(const InputField& inputField) const noexcept { std::ostringstream output; - output << _loader.getInputCppType(inputField) << R"cpp( )cpp" << inputField.cppName; + output << R"cpp( )cpp" << _loader.getInputCppType(inputField) << R"cpp( )cpp" + << inputField.cppName; return output.str(); } @@ -524,26 +1020,28 @@ std::string Generator::getFieldDeclaration(const OutputField& outputField) const std::string fieldName { outputField.cppName }; fieldName[0] = static_cast(std::toupper(static_cast(fieldName[0]))); - output << R"cpp( virtual service::FieldResult<)cpp" << _loader.getOutputCppType(outputField) - << R"cpp(> )cpp" << outputField.accessor << fieldName - << R"cpp((service::FieldParams&& params)cpp"; + output << R"cpp( virtual )cpp" << _loader.getOutputCppType(outputField) << R"cpp( )cpp" + << outputField.accessor << fieldName << R"cpp(()cpp"; - for (const auto& argument : outputField.arguments) - { - output << R"cpp(, )cpp" << _loader.getInputCppType(argument) << R"cpp(&& )cpp" - << argument.cppName << "Arg"; - } + bool firstArgument = _loader.isIntrospection(); - output << R"cpp() const)cpp"; - if (outputField.interfaceField || _loader.isIntrospection() || _options.noStubs) + if (!firstArgument) { - output << R"cpp( = 0)cpp"; + output << R"cpp(service::FieldParams&& params)cpp"; } - else if (outputField.inheritedField) + + for (const auto& argument : outputField.arguments) { - output << R"cpp( override)cpp"; + if (!firstArgument) + { + output << R"cpp(, )cpp"; + } + + output << _loader.getInputCppType(argument) << R"cpp(&& )cpp" << argument.cppName << "Arg"; + firstArgument = false; } - output << R"cpp(; + + output << R"cpp() const = 0; )cpp"; return output.str(); @@ -555,8 +1053,8 @@ std::string Generator::getResolverDeclaration(const OutputField& outputField) co std::string fieldName(outputField.cppName); fieldName[0] = static_cast(std::toupper(static_cast(fieldName[0]))); - output << R"cpp( std::future resolve)cpp" << fieldName - << R"cpp((service::ResolverParams&& params); + output << R"cpp( service::AwaitableResolver resolve)cpp" << fieldName + << R"cpp((service::ResolverParams&& params) const; )cpp"; return output.str(); @@ -572,17 +1070,32 @@ bool Generator::outputSource() const noexcept // WARNING! Do not edit this file manually, your changes will be overwritten. )cpp"; - - if (!_loader.isIntrospection()) + + if (!_loader.isIntrospection()) + { + for (const auto& operation : _loader.getOperationTypes()) + { + sourceFile << R"cpp(#include ")cpp" << operation.cppType << R"cpp(Object.h" +)cpp"; + } + + sourceFile << std::endl; + } + + if (_loader.isIntrospection()) + { + sourceFile << R"cpp(#include "graphqlservice/internal/Introspection.h" +)cpp"; + } + else { - sourceFile << R"cpp(#include ")cpp" << fs::path(_objectHeaderPath).filename().string() - << R"cpp(" + sourceFile << R"cpp(#include "graphqlservice/internal/Schema.h" +#include "graphqlservice/introspection/IntrospectionSchema.h" )cpp"; } - sourceFile << R"cpp(#include "graphqlservice/introspection/Introspection.h" - + sourceFile << R"cpp( #include #include #include @@ -622,7 +1135,7 @@ using namespace std::literals; } firstValue = false; - sourceFile << R"cpp( ")cpp" << value.value << R"cpp("sv)cpp"; + sourceFile << R"cpp( R"gql()cpp" << value.value << R"cpp()gql"sv)cpp"; } sourceFile << R"cpp( @@ -636,19 +1149,19 @@ template <> { if (!value.maybe_enum()) { - throw service::schema_exception { { "not a valid )cpp" - << enumType.type << R"cpp( value" } }; + throw service::schema_exception { { R"ex(not a valid )cpp" + << enumType.type << R"cpp( value)ex" } }; } const auto itr = std::find(s_names)cpp" << enumType.cppType << R"cpp(.cbegin(), s_names)cpp" << enumType.cppType - << R"cpp(.cend(), value.get()); + << R"cpp(.cend(), value.get()); if (itr == s_names)cpp" << enumType.cppType << R"cpp(.cend()) { - throw service::schema_exception { { "not a valid )cpp" - << enumType.type << R"cpp( value" } }; + throw service::schema_exception { { R"ex(not a valid )cpp" + << enumType.type << R"cpp( value)ex" } }; } return static_cast<)cpp" @@ -657,11 +1170,11 @@ template <> } template <> -std::future ModifiedResult<)cpp" +service::AwaitableResolver ModifiedResult<)cpp" << _loader.getSchemaNamespace() << R"cpp(::)cpp" << enumType.cppType - << R"cpp(>::convert(service::FieldResult<)cpp" + << R"cpp(>::convert(service::AwaitableScalar<)cpp" << _loader.getSchemaNamespace() << R"cpp(::)cpp" << enumType.cppType - << R"cpp(>&& result, ResolverParams&& params) + << R"cpp(> result, ResolverParams params) { return resolve(std::move(result), std::move(params), []()cpp" << _loader.getSchemaNamespace() @@ -669,13 +1182,36 @@ std::future ModifiedResult<)cpp" { response::Value result(response::Type::EnumValue); - result.set(response::StringType { s_names)cpp" + result.set(std::string { s_names)cpp" << enumType.cppType << R"cpp([static_cast(value)] }); return result; }); } +template <> +void ModifiedResult<)cpp" + << _loader.getSchemaNamespace() << R"cpp(::)cpp" << enumType.cppType + << R"cpp(>::validateScalar(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid )cpp" + << enumType.type << R"cpp( value)ex" } }; + } + + const auto itr = std::find(s_names)cpp" + << enumType.cppType << R"cpp(.cbegin(), s_names)cpp" << enumType.cppType + << R"cpp(.cend(), value.get()); + + if (itr == s_names)cpp" + << enumType.cppType << R"cpp(.cend()) + { + throw service::schema_exception { { R"ex(not a valid )cpp" + << enumType.type << R"cpp( value)ex" } }; + } +} + )cpp"; } @@ -779,19 +1315,6 @@ std::future ModifiedResult<)cpp" } } - if (!_loader.getObjectTypes().empty() && !_options.separateFiles) - { - NamespaceScope objectNamespace { sourceFile, "object" }; - - sourceFile << std::endl; - - for (const auto& objectType : _loader.getObjectTypes()) - { - outputObjectImplementation(sourceFile, objectType, objectType.type == queryType); - sourceFile << std::endl; - } - } - if (!_loader.isIntrospection()) { bool firstOperation = true; @@ -869,7 +1392,15 @@ Operations::Operations()cpp"; sourceFile << R"cpp(Built-in type)cpp"; } - sourceFile << R"cpp()md")); + sourceFile << R"cpp()md"sv, R"url()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << R"cpp(https://spec.graphql.org/October2021/#sec-)cpp" + << builtinType.first; + } + + sourceFile << R"cpp()url"sv)); )cpp"; } } @@ -887,7 +1418,14 @@ Operations::Operations()cpp"; sourceFile << scalarType.description; } - sourceFile << R"cpp()md")); + sourceFile << R"cpp()md", R"url()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << scalarType.specifiedByURL; + } + + sourceFile << R"cpp()url"sv)); )cpp"; } } @@ -933,43 +1471,43 @@ Operations::Operations()cpp"; } } - if (!_loader.getUnionTypes().empty()) + if (!_loader.getInterfaceTypes().empty()) { - for (const auto& unionType : _loader.getUnionTypes()) + for (const auto& interfaceType : _loader.getInterfaceTypes()) { - sourceFile << R"cpp( auto type)cpp" << unionType.cppType - << R"cpp( = schema::UnionType::Make(R"gql()cpp" << unionType.type + sourceFile << R"cpp( auto type)cpp" << interfaceType.cppType + << R"cpp( = schema::InterfaceType::Make(R"gql()cpp" << interfaceType.type << R"cpp()gql"sv, R"md()cpp"; if (!_options.noIntrospection) { - sourceFile << unionType.description; + sourceFile << interfaceType.description; } sourceFile << R"cpp()md"sv); schema->AddType(R"gql()cpp" - << unionType.type << R"cpp()gql"sv, type)cpp" << unionType.cppType + << interfaceType.type << R"cpp()gql"sv, type)cpp" << interfaceType.cppType << R"cpp(); )cpp"; } } - if (!_loader.getInterfaceTypes().empty()) + if (!_loader.getUnionTypes().empty()) { - for (const auto& interfaceType : _loader.getInterfaceTypes()) + for (const auto& unionType : _loader.getUnionTypes()) { - sourceFile << R"cpp( auto type)cpp" << interfaceType.cppType - << R"cpp( = schema::InterfaceType::Make(R"gql()cpp" << interfaceType.type + sourceFile << R"cpp( auto type)cpp" << unionType.cppType + << R"cpp( = schema::UnionType::Make(R"gql()cpp" << unionType.type << R"cpp()gql"sv, R"md()cpp"; if (!_options.noIntrospection) { - sourceFile << interfaceType.description; + sourceFile << unionType.description; } sourceFile << R"cpp()md"sv); schema->AddType(R"gql()cpp" - << interfaceType.type << R"cpp()gql"sv, type)cpp" << interfaceType.cppType + << unionType.type << R"cpp()gql"sv, type)cpp" << unionType.cppType << R"cpp(); )cpp"; } @@ -988,7 +1526,7 @@ Operations::Operations()cpp"; sourceFile << objectType.description; } - sourceFile << R"cpp()md"); + sourceFile << R"cpp()md"sv); schema->AddType(R"gql()cpp" << objectType.type << R"cpp()gql"sv, type)cpp" << objectType.cppType << R"cpp(); @@ -1093,127 +1631,27 @@ Operations::Operations()cpp"; } } - if (!_loader.getUnionTypes().empty()) + if (!_loader.getInterfaceTypes().empty()) { sourceFile << std::endl; - for (const auto& unionType : _loader.getUnionTypes()) + for (const auto& interfaceType : _loader.getInterfaceTypes()) { - if (!unionType.options.empty()) - { - bool firstValue = true; - - sourceFile << R"cpp( type)cpp" << unionType.cppType - << R"cpp(->AddPossibleTypes({ -)cpp"; - - for (const auto& unionOption : unionType.options) - { - if (!firstValue) - { - sourceFile << R"cpp(, -)cpp"; - } - - firstValue = false; - sourceFile << R"cpp( schema->LookupType(R"gql()cpp" << unionOption - << R"cpp()gql"sv))cpp"; - } - - sourceFile << R"cpp( - }); + sourceFile << R"cpp( Add)cpp" << interfaceType.cppType << R"cpp(Details(type)cpp" + << interfaceType.cppType << R"cpp(, schema); )cpp"; - } } } - if (!_loader.getInterfaceTypes().empty()) + if (!_loader.getUnionTypes().empty()) { sourceFile << std::endl; - for (const auto& interfaceType : _loader.getInterfaceTypes()) + for (const auto& unionType : _loader.getUnionTypes()) { - if (!interfaceType.fields.empty()) - { - bool firstValue = true; - - sourceFile << R"cpp( type)cpp" << interfaceType.cppType << R"cpp(->AddFields({ -)cpp"; - - for (const auto& interfaceField : interfaceType.fields) - { - if (!firstValue) - { - sourceFile << R"cpp(, -)cpp"; - } - - firstValue = false; - sourceFile << R"cpp( schema::Field::Make(R"gql()cpp" - << interfaceField.name << R"cpp()gql"sv, R"md()cpp"; - - if (!_options.noIntrospection) - { - sourceFile << interfaceField.description; - } - - sourceFile << R"cpp()md"sv, )cpp"; - - if (interfaceField.deprecationReason) - { - sourceFile << R"cpp(std::make_optional(R"md()cpp" - << *interfaceField.deprecationReason << R"cpp()md"sv))cpp"; - } - else - { - sourceFile << R"cpp(std::nullopt)cpp"; - } - - sourceFile << R"cpp(, )cpp" - << getIntrospectionType(interfaceField.type, - interfaceField.modifiers); - - if (!interfaceField.arguments.empty()) - { - bool firstArgument = true; - - sourceFile << R"cpp(, { + sourceFile << R"cpp( Add)cpp" << unionType.cppType << R"cpp(Details(type)cpp" + << unionType.cppType << R"cpp(, schema); )cpp"; - - for (const auto& argument : interfaceField.arguments) - { - if (!firstArgument) - { - sourceFile << R"cpp(, -)cpp"; - } - - firstArgument = false; - sourceFile << R"cpp( schema::InputValue::Make(R"gql()cpp" - << argument.name << R"cpp()gql"sv, R"md()cpp"; - - if (!_options.noIntrospection) - { - sourceFile << argument.description; - } - - sourceFile << R"cpp()md"sv, )cpp" - << getIntrospectionType(argument.type, argument.modifiers) - << R"cpp(, R"gql()cpp" << argument.defaultValueString - << R"cpp()gql"sv))cpp"; - } - - sourceFile << R"cpp( - })cpp"; - } - - sourceFile << R"cpp())cpp"; - } - - sourceFile << R"cpp( - }); -)cpp"; - } } } @@ -1223,16 +1661,9 @@ Operations::Operations()cpp"; for (const auto& objectType : _loader.getObjectTypes()) { - if (_options.separateFiles) - { - sourceFile << R"cpp( Add)cpp" << objectType.cppType << R"cpp(Details(type)cpp" - << objectType.cppType << R"cpp(, schema); + sourceFile << R"cpp( Add)cpp" << objectType.cppType << R"cpp(Details(type)cpp" + << objectType.cppType << R"cpp(, schema); )cpp"; - } - else - { - outputObjectIntrospection(sourceFile, objectType); - } } } @@ -1276,14 +1707,13 @@ Operations::Operations()cpp"; )cpp"; } - sourceFile << R"cpp(})cpp"; + sourceFile << R"cpp(}, {)cpp"; if (!directive.arguments.empty()) { bool firstArgument = true; - sourceFile << R"cpp(, { -)cpp"; + sourceFile << std::endl; for (const auto& argument : directive.arguments) { @@ -1309,9 +1739,11 @@ Operations::Operations()cpp"; } sourceFile << R"cpp( - })cpp"; + )cpp"; } - sourceFile << R"cpp()); + sourceFile << R"cpp(}, )cpp" + << (directive.isRepeatable ? R"cpp(true)cpp" : R"cpp(false)cpp") + << R"cpp()); )cpp"; } } @@ -1346,7 +1778,15 @@ Operations::Operations()cpp"; if (!schema) { schema = std::make_shared()cpp" - << (_options.noIntrospection ? "true" : "false") << R"cpp(); + << (_options.noIntrospection ? R"cpp(true)cpp" : R"cpp(false)cpp") + << R"cpp(, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << _loader.getSchemaDescription(); + } + + sourceFile << R"cpp()md"sv); )cpp" << SchemaLoader::getIntrospectionNamespace() << R"cpp(::AddTypesToSchema(schema); AddTypesToSchema(schema); @@ -1362,32 +1802,160 @@ Operations::Operations()cpp"; return true; } +void Generator::outputInterfaceImplementation( + std::ostream& sourceFile, std::string_view cppType) const +{ + // Output the private constructor which calls through to the service::Object constructor + // with arguments that declare the set of types it implements and bind the fields to the + // resolver methods. + sourceFile << cppType << R"cpp(::)cpp" << cppType + << R"cpp((std::unique_ptr&& pimpl) noexcept + : service::Object { pimpl->getTypeNames(), pimpl->getResolvers() } + , _pimpl { std::move(pimpl) } +{ +} +)cpp"; + + sourceFile << R"cpp( +void )cpp" << cppType + << R"cpp(::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} + +void )cpp" << cppType + << R"cpp(::endSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->endSelectionSet(params); +} +)cpp"; +} + +void Generator::outputInterfaceIntrospection( + std::ostream& sourceFile, const InterfaceType& interfaceType) const +{ + outputIntrospectionInterfaces(sourceFile, interfaceType.cppType, interfaceType.interfaces); + outputIntrospectionFields(sourceFile, interfaceType.cppType, interfaceType.fields); +} + +void Generator::outputUnionIntrospection(std::ostream& sourceFile, const UnionType& unionType) const +{ + if (unionType.options.empty()) + { + return; + } + + bool firstValue = true; + + sourceFile << R"cpp( type)cpp" << unionType.cppType << R"cpp(->AddPossibleTypes({ +)cpp"; + + for (const auto& unionOption : unionType.options) + { + if (!firstValue) + { + sourceFile << R"cpp(, +)cpp"; + } + + firstValue = false; + sourceFile << R"cpp( schema->LookupType(R"gql()cpp" << unionOption + << R"cpp()gql"sv))cpp"; + } + + sourceFile << R"cpp( + }); +)cpp"; +} + void Generator::outputObjectImplementation( std::ostream& sourceFile, const ObjectType& objectType, bool isQueryType) const { using namespace std::literals; - // Output the protected constructor which calls through to the service::Object constructor - // with arguments that declare the set of types it implements and bind the fields to the - // resolver methods. - sourceFile << objectType.cppType << R"cpp(::)cpp" << objectType.cppType << R"cpp(() - : service::Object({ + if (_loader.isIntrospection()) + { + // Output the public constructor which calls through to the service::Object constructor + // with arguments that declare the set of types it implements and bind the fields to the + // resolver methods. + sourceFile << objectType.cppType << R"cpp(::)cpp" << objectType.cppType + << R"cpp((std::shared_ptr<)cpp" << SchemaLoader::getIntrospectionNamespace() + << R"cpp(::)cpp" << objectType.cppType << R"cpp(> pimpl))cpp"; + } + else + { + // Output the private constructor which calls through to the service::Object constructor + // with arguments that declare the set of types it implements and bind the fields to the + // resolver methods. + sourceFile << objectType.cppType << R"cpp(::)cpp" << objectType.cppType + << R"cpp((std::unique_ptr&& pimpl))cpp"; + } + + sourceFile << R"cpp( noexcept + : service::Object{ getTypeNames(), getResolvers() })cpp"; + + if (!_options.noIntrospection && isQueryType) + { + sourceFile << R"cpp( + , _schema { GetSchema() })cpp"; + } + + if (_loader.isIntrospection()) + { + sourceFile << R"cpp( + , _pimpl { std::make_unique>(std::move(pimpl)) })cpp"; + } + else + { + sourceFile << R"cpp( + , _pimpl { std::move(pimpl) })cpp"; + } + sourceFile << R"cpp( +{ +} +)cpp"; + + if (_loader.isIntrospection()) + { + sourceFile << R"cpp( +)cpp" << objectType.cppType + << R"cpp(::~)cpp" << objectType.cppType << R"cpp(() +{ + // This is empty, but explicitly defined here so that it can access the un-exported destructor + // of the implementation type. +} +)cpp"; + } + + sourceFile << R"cpp( +service::TypeNames )cpp" + << objectType.cppType << R"cpp(::getTypeNames() const noexcept +{ + return { )cpp"; for (const auto& interfaceName : objectType.interfaces) { - sourceFile << R"cpp( ")cpp" << interfaceName << R"cpp(", + sourceFile << R"cpp( R"gql()cpp" << interfaceName << R"cpp()gql"sv, )cpp"; } for (const auto& unionName : objectType.unions) { - sourceFile << R"cpp( ")cpp" << unionName << R"cpp(", + sourceFile << R"cpp( R"gql()cpp" << unionName << R"cpp()gql"sv, )cpp"; } - sourceFile << R"cpp( ")cpp" << objectType.type << R"cpp(" - }, { + sourceFile << R"cpp( R"gql()cpp" << objectType.type << R"cpp()gql"sv + }; +} + +service::ResolverMap )cpp" + << objectType.cppType << R"cpp(::getResolvers() const noexcept +{ + return { )cpp"; std::map resolvers; @@ -1436,18 +2004,26 @@ void Generator::outputObjectImplementation( } sourceFile << R"cpp( - }))cpp"; + }; +} +)cpp"; - if (!_options.noIntrospection && isQueryType) + if (!_loader.isIntrospection()) { sourceFile << R"cpp( - , _schema(GetSchema()))cpp"; - } +void )cpp" << objectType.cppType + << R"cpp(::beginSelectionSet(const service::SelectionSetParams& params) const +{ + _pimpl->beginSelectionSet(params); +} - sourceFile << R"cpp( +void )cpp" << objectType.cppType + << R"cpp(::endSelectionSet(const service::SelectionSetParams& params) const { + _pimpl->endSelectionSet(params); } )cpp"; + } // Output each of the resolver implementations, which call the virtual property // getters that the implementer must define. @@ -1455,32 +2031,12 @@ void Generator::outputObjectImplementation( { std::string fieldName(outputField.cppName); - fieldName[0] = static_cast(std::toupper(static_cast(fieldName[0]))); - if (!_loader.isIntrospection() && !_options.noStubs) - { - sourceFile << R"cpp( -service::FieldResult<)cpp" - << _loader.getOutputCppType(outputField) << R"cpp(> )cpp" - << objectType.cppType << R"cpp(::)cpp" << outputField.accessor << fieldName - << R"cpp((service::FieldParams&&)cpp"; - for (const auto& argument : outputField.arguments) - { - sourceFile << R"cpp(, )cpp" << _loader.getInputCppType(argument) << R"cpp(&&)cpp"; - } - - sourceFile << R"cpp() const -{ - throw std::runtime_error(R"ex()cpp" - << objectType.cppType << R"cpp(::)cpp" << outputField.accessor << fieldName - << R"cpp( is not implemented)ex"); -} -)cpp"; - } + fieldName[0] = static_cast(std::toupper(static_cast(fieldName[0]))); sourceFile << R"cpp( -std::future )cpp" +service::AwaitableResolver )cpp" << objectType.cppType << R"cpp(::resolve)cpp" << fieldName - << R"cpp((service::ResolverParams&& params) + << R"cpp((service::ResolverParams&& params) const { )cpp"; @@ -1496,7 +2052,7 @@ std::future )cpp" if (firstArgument) { firstArgument = false; - sourceFile << R"cpp( const auto defaultArguments = []() + sourceFile << R"cpp( static const auto defaultArguments = []() { response::Value values(response::Type::Map); response::Value entry; @@ -1530,10 +2086,24 @@ std::future )cpp" } sourceFile << R"cpp( std::unique_lock resolverLock(_resolverMutex); - auto directives = std::move(params.fieldDirectives); - auto result = )cpp" - << outputField.accessor << fieldName - << R"cpp((service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)))cpp"; +)cpp"; + + if (!_loader.isIntrospection()) + { + sourceFile << R"cpp( auto directives = std::move(params.fieldDirectives); +)cpp"; + } + + sourceFile << R"cpp( auto result = _pimpl->)cpp" << outputField.accessor << fieldName + << R"cpp(()cpp"; + + bool firstArgument = _loader.isIntrospection(); + + if (!firstArgument) + { + sourceFile + << R"cpp(service::FieldParams(service::SelectionSetParams{ params }, std::move(directives)))cpp"; + } if (!outputField.arguments.empty()) { @@ -1543,7 +2113,14 @@ std::future )cpp" argumentName[0] = static_cast(std::toupper(static_cast(argumentName[0]))); - sourceFile << R"cpp(, std::move(arg)cpp" << argumentName << R"cpp())cpp"; + + if (!firstArgument) + { + sourceFile << R"cpp(, )cpp"; + } + + sourceFile << R"cpp(std::move(arg)cpp" << argumentName << R"cpp())cpp"; + firstArgument = false; } } @@ -1558,10 +2135,11 @@ std::future )cpp" } sourceFile << R"cpp( -std::future )cpp" - << objectType.cppType << R"cpp(::resolve_typename(service::ResolverParams&& params) +service::AwaitableResolver )cpp" + << objectType.cppType + << R"cpp(::resolve_typename(service::ResolverParams&& params) const { - return service::ModifiedResult::convert(response::StringType{ R"gql()cpp" + return service::ModifiedResult::convert(std::string{ R"gql()cpp" << objectType.type << R"cpp()gql" }, std::move(params)); } )cpp"; @@ -1570,23 +2148,27 @@ std::future )cpp" { sourceFile << R"cpp( -std::future )cpp" - << objectType.cppType << R"cpp(::resolve_schema(service::ResolverParams&& params) +service::AwaitableResolver )cpp" + << objectType.cppType << R"cpp(::resolve_schema(service::ResolverParams&& params) const { return service::ModifiedResult::convert(std::static_pointer_cast(std::make_shared<)cpp" << SchemaLoader::getIntrospectionNamespace() - << R"cpp(::Schema>(_schema)), std::move(params)); + << R"cpp(::object::Schema>(std::make_shared<)cpp" + << SchemaLoader::getIntrospectionNamespace() + << R"cpp(::Schema>(_schema))), std::move(params)); } -std::future )cpp" - << objectType.cppType << R"cpp(::resolve_type(service::ResolverParams&& params) +service::AwaitableResolver )cpp" + << objectType.cppType << R"cpp(::resolve_type(service::ResolverParams&& params) const { - auto argName = service::ModifiedArgument::require("name", params.arguments); + auto argName = service::ModifiedArgument::require("name", params.arguments); const auto& baseType = _schema->LookupType(argName); std::shared_ptr<)cpp" << SchemaLoader::getIntrospectionNamespace() << R"cpp(::object::Type> result { baseType ? std::make_shared<)cpp" - << SchemaLoader::getIntrospectionNamespace() << R"cpp(::Type>(baseType) : nullptr }; + << SchemaLoader::getIntrospectionNamespace() + << R"cpp(::object::Type>(std::make_shared<)cpp" + << SchemaLoader::getIntrospectionNamespace() << R"cpp(::Type>(baseType)) : nullptr }; return service::ModifiedResult<)cpp" << SchemaLoader::getIntrospectionNamespace() @@ -1599,14 +2181,21 @@ std::future )cpp" void Generator::outputObjectIntrospection( std::ostream& sourceFile, const ObjectType& objectType) const { - if (!objectType.interfaces.empty()) + outputIntrospectionInterfaces(sourceFile, objectType.cppType, objectType.interfaces); + outputIntrospectionFields(sourceFile, objectType.cppType, objectType.fields); +} + +void Generator::outputIntrospectionInterfaces(std::ostream& sourceFile, std::string_view cppType, + const std::vector& interfaces) const +{ + if (!interfaces.empty()) { bool firstInterface = true; - sourceFile << R"cpp( type)cpp" << objectType.cppType << R"cpp(->AddInterfaces({ + sourceFile << R"cpp( type)cpp" << cppType << R"cpp(->AddInterfaces({ )cpp"; - for (const auto& interfaceName : objectType.interfaces) + for (const auto& interfaceName : interfaces) { if (!firstInterface) { @@ -1616,103 +2205,102 @@ void Generator::outputObjectIntrospection( firstInterface = false; - if (_options.separateFiles) - { - sourceFile - << R"cpp( std::static_pointer_cast(schema->LookupType(R"gql()cpp" - << interfaceName << R"cpp()gql"sv)))cpp"; - } - else - { - sourceFile << R"cpp( type)cpp" << _loader.getSafeCppName(interfaceName); - } + sourceFile + << R"cpp( std::static_pointer_cast(schema->LookupType(R"gql()cpp" + << interfaceName << R"cpp()gql"sv)))cpp"; } sourceFile << R"cpp( }); )cpp"; } +} - if (!objectType.fields.empty()) +void Generator::outputIntrospectionFields( + std::ostream& sourceFile, std::string_view cppType, const OutputFieldList& fields) const +{ + if (fields.empty()) { - bool firstValue = true; + return; + } - sourceFile << R"cpp( type)cpp" << objectType.cppType << R"cpp(->AddFields({ + bool firstValue = true; + + sourceFile << R"cpp( type)cpp" << cppType << R"cpp(->AddFields({ )cpp"; - for (const auto& objectField : objectType.fields) + for (const auto& objectField : fields) + { + if (!firstValue) { - if (!firstValue) - { - sourceFile << R"cpp(, + sourceFile << R"cpp(, )cpp"; - } + } - firstValue = false; - sourceFile << R"cpp( schema::Field::Make(R"gql()cpp" << objectField.name - << R"cpp()gql"sv, R"md()cpp"; + firstValue = false; + sourceFile << R"cpp( schema::Field::Make(R"gql()cpp" << objectField.name + << R"cpp()gql"sv, R"md()cpp"; - if (!_options.noIntrospection) - { - sourceFile << objectField.description; - } + if (!_options.noIntrospection) + { + sourceFile << objectField.description; + } - sourceFile << R"cpp()md"sv, )cpp"; + sourceFile << R"cpp()md"sv, )cpp"; - if (objectField.deprecationReason) - { - sourceFile << R"cpp(std::make_optional(R"md()cpp" << *objectField.deprecationReason - << R"cpp()md"sv))cpp"; - } - else - { - sourceFile << R"cpp(std::nullopt)cpp"; - } + if (objectField.deprecationReason) + { + sourceFile << R"cpp(std::make_optional(R"md()cpp" << *objectField.deprecationReason + << R"cpp()md"sv))cpp"; + } + else + { + sourceFile << R"cpp(std::nullopt)cpp"; + } - sourceFile << R"cpp(, )cpp" - << getIntrospectionType(objectField.type, objectField.modifiers); + sourceFile << R"cpp(, )cpp" + << getIntrospectionType(objectField.type, objectField.modifiers); - if (!objectField.arguments.empty()) - { - bool firstArgument = true; + if (!objectField.arguments.empty()) + { + bool firstArgument = true; - sourceFile << R"cpp(, { + sourceFile << R"cpp(, { )cpp"; - for (const auto& argument : objectField.arguments) + for (const auto& argument : objectField.arguments) + { + if (!firstArgument) { - if (!firstArgument) - { - sourceFile << R"cpp(, + sourceFile << R"cpp(, )cpp"; - } - - firstArgument = false; - sourceFile << R"cpp( schema::InputValue::Make(R"gql()cpp" - << argument.name << R"cpp()gql"sv, R"md()cpp"; + } - if (!_options.noIntrospection) - { - sourceFile << argument.description; - } + firstArgument = false; + sourceFile << R"cpp( schema::InputValue::Make(R"gql()cpp" + << argument.name << R"cpp()gql"sv, R"md()cpp"; - sourceFile << R"cpp()md"sv, )cpp" - << getIntrospectionType(argument.type, argument.modifiers) - << R"cpp(, R"gql()cpp" << argument.defaultValueString - << R"cpp()gql"sv))cpp"; + if (!_options.noIntrospection) + { + sourceFile << argument.description; } - sourceFile << R"cpp( - })cpp"; + sourceFile << R"cpp()md"sv, )cpp" + << getIntrospectionType(argument.type, argument.modifiers) + << R"cpp(, R"gql()cpp" << argument.defaultValueString + << R"cpp()gql"sv))cpp"; } - sourceFile << R"cpp())cpp"; + sourceFile << R"cpp( + })cpp"; } - sourceFile << R"cpp( + sourceFile << R"cpp())cpp"; + } + + sourceFile << R"cpp( }); )cpp"; - } } std::string Generator::getArgumentDefaultValue( @@ -1776,7 +2364,7 @@ std::string Generator::getArgumentDefaultValue( { argumentDefaultValue << padding << R"cpp( entry = response::Value(std::string(R"gql()cpp" - << defaultValue.get() << R"cpp()gql")); + << defaultValue.get() << R"cpp()gql")); )cpp"; break; } @@ -1791,8 +2379,7 @@ std::string Generator::getArgumentDefaultValue( case response::Type::Boolean: { argumentDefaultValue << padding << R"cpp( entry = response::Value()cpp" - << (defaultValue.get() ? R"cpp(true)cpp" - : R"cpp(false)cpp") + << (defaultValue.get() ? R"cpp(true)cpp" : R"cpp(false)cpp") << R"cpp(); )cpp"; break; @@ -1800,20 +2387,18 @@ std::string Generator::getArgumentDefaultValue( case response::Type::Int: { - argumentDefaultValue - << padding - << R"cpp( entry = response::Value(static_cast()cpp" - << defaultValue.get() << R"cpp()); + argumentDefaultValue << padding + << R"cpp( entry = response::Value(static_cast()cpp" + << defaultValue.get() << R"cpp()); )cpp"; break; } case response::Type::Float: { - argumentDefaultValue - << padding - << R"cpp( entry = response::Value(static_cast()cpp" - << defaultValue.get() << R"cpp()); + argumentDefaultValue << padding + << R"cpp( entry = response::Value(static_cast()cpp" + << defaultValue.get() << R"cpp()); )cpp"; break; } @@ -1822,8 +2407,8 @@ std::string Generator::getArgumentDefaultValue( { argumentDefaultValue << padding << R"cpp( entry = response::Value(response::Type::EnumValue); - entry.set(R"gql()cpp" - << defaultValue.get() << R"cpp()gql"); + entry.set(R"gql()cpp" + << defaultValue.get() << R"cpp()gql"); )cpp"; break; } @@ -1924,6 +2509,8 @@ std::string Generator::getResultAccessType(const OutputField& result) const noex { case OutputFieldType::Builtin: case OutputFieldType::Enum: + case OutputFieldType::Interface: + case OutputFieldType::Union: case OutputFieldType::Object: resultType << _loader.getCppType(result.type); break; @@ -1931,11 +2518,6 @@ std::string Generator::getResultAccessType(const OutputField& result) const noex case OutputFieldType::Scalar: resultType << R"cpp(response::Value)cpp"; break; - - case OutputFieldType::Union: - case OutputFieldType::Interface: - resultType << R"cpp(service::Object)cpp"; - break; } resultType << R"cpp(>)cpp"; @@ -2046,7 +2628,7 @@ std::string Generator::getIntrospectionType( ++wrapperCount; } - introspectionType << R"cpp(schema->LookupType(")cpp" << type << R"cpp("))cpp"; + introspectionType << R"cpp(schema->LookupType(R"gql()cpp" << type << R"cpp()gql"sv))cpp"; for (size_t i = 0; i < wrapperCount; ++i) { @@ -2058,9 +2640,9 @@ std::string Generator::getIntrospectionType( std::vector Generator::outputSeparateFiles() const noexcept { + const std::filesystem::path headerDir(_headerDir); + const std::filesystem::path sourceDir(_sourceDir); std::vector files; - const fs::path headerDir(_headerDir); - const fs::path sourceDir(_sourceDir); std::string_view queryType; for (const auto& operation : _loader.getOperationTypes()) @@ -2072,56 +2654,211 @@ std::vector Generator::outputSeparateFiles() const noexcept } } - // Output a convenience header - std::ofstream objectHeaderFile(_objectHeaderPath, std::ios_base::trunc); - IncludeGuardScope includeGuard { objectHeaderFile, - fs::path(_objectHeaderPath).filename().string() }; + std::ostringstream ossNamespace; - objectHeaderFile << R"cpp(#include ")cpp" << fs::path(_headerPath).filename().string() - << R"cpp(" + ossNamespace << R"cpp(graphql::)cpp" << _loader.getSchemaNamespace(); -)cpp"; + const auto schemaNamespace = ossNamespace.str(); + std::ostringstream ossInterfaceNamespace; - for (const auto& objectType : _loader.getObjectTypes()) + ossInterfaceNamespace << schemaNamespace << R"cpp(::object)cpp"; + + const auto objectNamespace = ossInterfaceNamespace.str(); + + for (const auto& interfaceType : _loader.getInterfaceTypes()) { - const auto headerFilename = std::string(objectType.cppType) + "Object.h"; + const auto headerFilename = std::string(interfaceType.cppType) + "Object.h"; + auto headerPath = (headerDir / headerFilename).string(); + + { + std::ofstream headerFile(headerPath, std::ios_base::trunc); + IncludeGuardScope includeGuard { headerFile, headerFilename }; + + headerFile << R"cpp(#include ")cpp" + << std::filesystem::path(_headerPath).filename().string() << R"cpp(" - objectHeaderFile << R"cpp(#include ")cpp" << headerFilename << R"cpp(" )cpp"; - } - if (_options.verbose) - { - files.push_back({ _objectHeaderPath }); + NamespaceScope headerNamespace { headerFile, objectNamespace }; + + // Output the full declaration + headerFile << std::endl; + outputInterfaceDeclaration(headerFile, interfaceType.cppType); + headerFile << std::endl; + + if (_options.verbose) + { + files.push_back(std::move(headerPath)); + } + } + + const auto sourceFilename = std::string(interfaceType.cppType) + "Object.cpp"; + auto sourcePath = (sourceDir / sourceFilename).string(); + + { + std::ofstream sourceFile(sourcePath, std::ios_base::trunc); + + sourceFile << R"cpp(// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include ")cpp" << headerFilename + << R"cpp(" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +)cpp"; + + NamespaceScope sourceSchemaNamespace { sourceFile, schemaNamespace }; + NamespaceScope sourceInterfaceNamespace { sourceFile, "object" }; + + sourceFile << std::endl; + outputInterfaceImplementation(sourceFile, interfaceType.cppType); + sourceFile << std::endl; + + sourceInterfaceNamespace.exit(); + sourceFile << std::endl; + + sourceFile << R"cpp(void Add)cpp" << interfaceType.cppType + << R"cpp(Details(const std::shared_ptr& type)cpp" + << interfaceType.cppType + << R"cpp(, const std::shared_ptr& schema) +{ +)cpp"; + outputInterfaceIntrospection(sourceFile, interfaceType); + sourceFile << R"cpp(} + +)cpp"; + } + + files.push_back(std::move(sourcePath)); } - for (const auto& objectType : _loader.getObjectTypes()) + for (const auto& unionType : _loader.getUnionTypes()) { - std::ostringstream ossNamespace; + const auto headerFilename = std::string(unionType.cppType) + "Object.h"; + auto headerPath = (headerDir / headerFilename).string(); + + { + std::ofstream headerFile(headerPath, std::ios_base::trunc); + IncludeGuardScope includeGuard { headerFile, headerFilename }; + + headerFile << R"cpp(#include ")cpp" + << std::filesystem::path(_headerPath).filename().string() << R"cpp(" + +)cpp"; + + NamespaceScope headerNamespace { headerFile, objectNamespace }; + + // Output the full declaration + headerFile << std::endl; + outputInterfaceDeclaration(headerFile, unionType.cppType); + headerFile << std::endl; + } + + if (_options.verbose) + { + files.push_back(std::move(headerPath)); + } + + const auto sourceFilename = std::string(unionType.cppType) + "Object.cpp"; + auto sourcePath = (sourceDir / sourceFilename).string(); + + { + std::ofstream sourceFile(sourcePath, std::ios_base::trunc); + + sourceFile << R"cpp(// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include ")cpp" << headerFilename + << R"cpp(" + +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; - ossNamespace << R"cpp(graphql::)cpp" << _loader.getSchemaNamespace(); +)cpp"; + + NamespaceScope sourceSchemaNamespace { sourceFile, schemaNamespace }; + NamespaceScope sourceUnionNamespace { sourceFile, "object" }; + + sourceFile << std::endl; + outputInterfaceImplementation(sourceFile, unionType.cppType); + sourceFile << std::endl; + + sourceUnionNamespace.exit(); + sourceFile << std::endl; + + sourceFile << R"cpp(void Add)cpp" << unionType.cppType + << R"cpp(Details(const std::shared_ptr& type)cpp" + << unionType.cppType + << R"cpp(, const std::shared_ptr& schema) +{ +)cpp"; + outputUnionIntrospection(sourceFile, unionType); + sourceFile << R"cpp(} - const auto schemaNamespace = ossNamespace.str(); +)cpp"; + } - ossNamespace << R"cpp(::object)cpp"; + files.push_back(std::move(sourcePath)); + } - const auto objectNamespace = ossNamespace.str(); + for (const auto& objectType : _loader.getObjectTypes()) + { const bool isQueryType = objectType.type == queryType; const auto headerFilename = std::string(objectType.cppType) + "Object.h"; auto headerPath = (headerDir / headerFilename).string(); - std::ofstream headerFile(headerPath, std::ios_base::trunc); - IncludeGuardScope includeGuard { headerFile, headerFilename }; - headerFile << R"cpp(#include ")cpp" << fs::path(_headerPath).filename().string() << R"cpp(" + { + std::ofstream headerFile(headerPath, std::ios_base::trunc); + IncludeGuardScope includeGuard { headerFile, headerFilename }; + + headerFile << R"cpp(#include ")cpp" + << std::filesystem::path(_headerPath).filename().string() << R"cpp(" )cpp"; - NamespaceScope headerNamespace { headerFile, objectNamespace }; + NamespaceScope headerNamespace { headerFile, objectNamespace }; - // Output the full declaration - headerFile << std::endl; - outputObjectDeclaration(headerFile, objectType, isQueryType); - headerFile << std::endl; + if (!_loader.isIntrospection()) + { + if (!objectType.interfaces.empty() || !objectType.unions.empty()) + { + NamespaceScope implementsNamespace { headerFile, R"cpp(implements)cpp" }; + + headerFile << std::endl; + outputObjectImplements(headerFile, objectType); + + implementsNamespace.exit(); + headerFile << std::endl; + } + + // Output the stub concepts + std::ostringstream ossConceptNamespace; + + ossConceptNamespace << R"cpp(methods::)cpp" << objectType.cppType << R"cpp(Has)cpp"; + + const auto conceptNamespace = ossConceptNamespace.str(); + NamespaceScope stubNamespace { headerFile, conceptNamespace }; + + outputObjectStubs(headerFile, objectType); + } + + // Output the full declaration + headerFile << std::endl; + outputObjectDeclaration(headerFile, objectType, isQueryType); + headerFile << std::endl; + } if (_options.verbose) { @@ -2130,18 +2867,65 @@ std::vector Generator::outputSeparateFiles() const noexcept const auto sourceFilename = std::string(objectType.cppType) + "Object.cpp"; auto sourcePath = (sourceDir / sourceFilename).string(); - std::ofstream sourceFile(sourcePath, std::ios_base::trunc); - sourceFile << R"cpp(// Copyright (c) Microsoft Corporation. All rights reserved. + { + std::ofstream sourceFile(sourcePath, std::ios_base::trunc); + + sourceFile << R"cpp(// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // WARNING! Do not edit this file manually, your changes will be overwritten. -#include ")cpp" << fs::path(_objectHeaderPath).filename().string() - << R"cpp(" +#include ")cpp" << headerFilename + << R"cpp(" +)cpp"; + + std::unordered_set includedObjects; + + for (const auto& field : objectType.fields) + { + switch (field.fieldType) + { + case OutputFieldType::Interface: + case OutputFieldType::Union: + case OutputFieldType::Object: + if (includedObjects.insert(field.type).second) + { + sourceFile << R"cpp(#include ")cpp" + << _loader.getSafeCppName(field.type) << R"cpp(Object.h" +)cpp"; + } + break; + + default: + break; + } + } + + if (_loader.isIntrospection() || (isQueryType && !_options.noIntrospection)) + { + sourceFile << R"cpp( +#include "graphqlservice/internal/Introspection.h" +)cpp"; + } + else + { + sourceFile << R"cpp( +#include "graphqlservice/internal/Schema.h" + +#include "graphqlservice/introspection/IntrospectionSchema.h" +)cpp"; + } -#include "graphqlservice/introspection/Introspection.h" + if (isQueryType && !_options.noIntrospection) + { + sourceFile << R"cpp( +#include "graphqlservice/introspection/SchemaObject.h" +#include "graphqlservice/introspection/TypeObject.h" +)cpp"; + } + sourceFile << R"cpp( #include #include #include @@ -2152,25 +2936,27 @@ using namespace std::literals; )cpp"; - NamespaceScope sourceSchemaNamespace { sourceFile, schemaNamespace }; - NamespaceScope sourceObjectNamespace { sourceFile, "object" }; + NamespaceScope sourceSchemaNamespace { sourceFile, schemaNamespace }; + NamespaceScope sourceObjectNamespace { sourceFile, "object" }; - sourceFile << std::endl; - outputObjectImplementation(sourceFile, objectType, isQueryType); - sourceFile << std::endl; + sourceFile << std::endl; + outputObjectImplementation(sourceFile, objectType, isQueryType); + sourceFile << std::endl; - sourceObjectNamespace.exit(); - sourceFile << std::endl; + sourceObjectNamespace.exit(); + sourceFile << std::endl; - sourceFile << R"cpp(void Add)cpp" << objectType.cppType - << R"cpp(Details(std::shared_ptr type)cpp" - << objectType.cppType << R"cpp(, const std::shared_ptr& schema) + sourceFile << R"cpp(void Add)cpp" << objectType.cppType + << R"cpp(Details(const std::shared_ptr& type)cpp" + << objectType.cppType + << R"cpp(, const std::shared_ptr& schema) { )cpp"; - outputObjectIntrospection(sourceFile, objectType); - sourceFile << R"cpp(} + outputObjectIntrospection(sourceFile, objectType); + sourceFile << R"cpp(} )cpp"; + } files.push_back(std::move(sourcePath)); } @@ -2204,9 +2990,8 @@ int main(int argc, char** argv) bool showVersion = false; bool buildIntrospection = false; bool buildCustom = false; - bool noStubs = false; bool verbose = false; - bool separateFiles = false; + bool stubs = false; bool noIntrospection = false; std::string schemaFileName; std::string filenamePrefix; @@ -2229,11 +3014,10 @@ int main(int argc, char** argv) po::value(&sourceDir), "Target path for the Schema.cpp source file")("header-dir", po::value(&headerDir), - "Target path for the Schema.h header file")("no-stubs", - po::bool_switch(&noStubs), - "Generate abstract classes without stub implementations")("separate-files", - po::bool_switch(&separateFiles), - "Generate separate files for each of the types")("no-introspection", + "Target path for the Schema.h header file")("stubs", + po::bool_switch(&stubs), + "Unimplemented fields throw runtime exceptions instead of compiler errors")("no-" + "introspection", po::bool_switch(&noIntrospection), "Do not generate support for Introspection"); positional.add("schema", 1).add("prefix", 1).add("namespace", 1); @@ -2283,7 +3067,7 @@ int main(int argc, char** argv) outputVersion(std::cout); return 0; } - else if (showUsage || (!buildIntrospection && !buildCustom)) + else if (showUsage || !buildCustom) { outputUsage(std::cout, options); return 0; @@ -2291,38 +3075,21 @@ int main(int argc, char** argv) try { - if (buildIntrospection) - { - const auto files = - graphql::generator::schema::Generator(std::nullopt, { std::nullopt, verbose }) - .Build(); - - for (const auto& file : files) + const auto files = graphql::generator::schema::Generator({ std::move(schemaFileName), + std::move(filenamePrefix), + std::move(schemaNamespace), + buildIntrospection }, { - std::cout << file << std::endl; - } - } + { std::move(headerDir), std::move(sourceDir) }, // paths + verbose, // verbose + stubs, // stubs + noIntrospection, // noIntrospection + }) + .Build(); - if (buildCustom) + for (const auto& file : files) { - const auto files = graphql::generator::schema::Generator( - std::make_optional(graphql::generator::SchemaOptions { std::move(schemaFileName), - std::move(filenamePrefix), - std::move(schemaNamespace) }), - { - graphql::generator::schema::GeneratorPaths { std::move(headerDir), - std::move(sourceDir) }, - verbose, - separateFiles, - noStubs, - noIntrospection, - }) - .Build(); - - for (const auto& file : files) - { - std::cout << file << std::endl; - } + std::cout << file << std::endl; } } catch (const graphql::peg::parse_error& pe) diff --git a/src/SchemaLoader.cpp b/src/SchemaLoader.cpp index cd347d79..daeca935 100644 --- a/src/SchemaLoader.cpp +++ b/src/SchemaLoader.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -25,142 +26,26 @@ const BuiltinTypeMap SchemaLoader::s_builtinTypes = { }; const CppTypeMap SchemaLoader::s_builtinCppTypes = { - "response::IntType"sv, - "response::FloatType"sv, - "response::StringType"sv, - "response::BooleanType"sv, + "int"sv, + "double"sv, + "std::string"sv, + "bool"sv, "response::IdType"sv, }; const std::string_view SchemaLoader::s_scalarCppType = R"cpp(response::Value)cpp"sv; -SchemaLoader::SchemaLoader(std::optional&& customSchema) - : _customSchema(std::move(customSchema)) - , _isIntrospection(!_customSchema) - , _schemaNamespace(_isIntrospection ? s_introspectionNamespace : _customSchema->schemaNamespace) +SchemaLoader::SchemaLoader(SchemaOptions&& schemaOptions) + : _schemaOptions(std::move(schemaOptions)) + , _isIntrospection(_schemaOptions.isIntrospection) + , _schemaNamespace(_schemaOptions.schemaNamespace) { - if (_isIntrospection) - { - // Introspection Schema: - // http://spec.graphql.org/June2018/#sec-Schema-Introspection - _ast = peg::parseSchemaString(R"gql( - type __Schema { - types: [__Type!]! - queryType: __Type! - mutationType: __Type - subscriptionType: __Type - directives: [__Directive!]! - } - - type __Type { - kind: __TypeKind! - name: String - description: String - - # OBJECT and INTERFACE only - fields(includeDeprecated: Boolean = false): [__Field!] - - # OBJECT only - interfaces: [__Type!] - - # INTERFACE and UNION only - possibleTypes: [__Type!] - - # ENUM only - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - - # INPUT_OBJECT only - inputFields: [__InputValue!] - - # NON_NULL and LIST only - ofType: __Type - } - - type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - } - - type __InputValue { - name: String! - description: String - type: __Type! - defaultValue: String - } - - type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - } - - enum __TypeKind { - SCALAR - OBJECT - INTERFACE - UNION - ENUM - INPUT_OBJECT - LIST - NON_NULL - } - - type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - } - - enum __DirectiveLocation { - QUERY - MUTATION - SUBSCRIPTION - FIELD - FRAGMENT_DEFINITION - FRAGMENT_SPREAD - INLINE_FRAGMENT - SCHEMA - SCALAR - OBJECT - FIELD_DEFINITION - ARGUMENT_DEFINITION - INTERFACE - UNION - ENUM - ENUM_VALUE - INPUT_OBJECT - INPUT_FIELD_DEFINITION - } + _ast = peg::parseSchemaFile(_schemaOptions.schemaFilename); - # These directives are always defined and should be included in the Introspection schema. - directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - directive @deprecated( - reason: String = "No longer supported" - ) on FIELD_DEFINITION | ENUM_VALUE - )gql"sv); - - if (!_ast.root) - { - throw std::logic_error("Unable to parse the introspection schema, but there was no " - "error message from the parser!"); - } - } - else + if (!_ast.root) { - _ast = peg::parseSchemaFile(_customSchema->schemaFilename); - - if (!_ast.root) - { - throw std::logic_error("Unable to parse the service schema, but there was no error " - "message from the parser!"); - } + throw std::logic_error("Unable to parse the service schema, but there was no error " + "message from the parser!"); } for (const auto& child : _ast.root->children) @@ -202,6 +87,9 @@ void SchemaLoader::validateSchema() // Handle nested input types by fully declaring the dependencies first. reorderInputTypeDependencies(); + // Validate the interface dependencies and that all of the interface fields are implemented. + validateImplementedInterfaces(); + for (auto& entry : _interfaceTypes) { fixupOutputFieldList(entry.fields, std::nullopt, std::nullopt); @@ -302,30 +190,6 @@ void SchemaLoader::validateSchema() fixupOutputFieldList(entry.fields, interfaceFields, accessor); } - // Validate the interfaces implemented by the object types. - for (const auto& entry : _objectTypes) - { - for (const auto& interfaceName : entry.interfaces) - { - if (_interfaceNames.find(interfaceName) == _interfaceNames.cend()) - { - std::ostringstream error; - auto itrPosition = _typePositions.find(entry.type); - - error << "Unknown interface: " << interfaceName - << " implemented by: " << entry.type; - - if (itrPosition != _typePositions.cend()) - { - error << " line: " << itrPosition->second.line - << " column: " << itrPosition->second.column; - } - - throw std::runtime_error(error.str()); - } - } - } - // Validate the objects that are possible types for unions and add the unions to // the list of matching types for the objects. for (const auto& entry : _unionTypes) @@ -549,6 +413,29 @@ void SchemaLoader::reorderInputTypeDependencies() } } +void SchemaLoader::validateImplementedInterfaces() const +{ + for (const auto& interfaceType : _interfaceTypes) + { + validateTransitiveInterfaces(interfaceType.type, interfaceType.interfaces); + + for (auto interfaceName : interfaceType.interfaces) + { + validateInterfaceFields(interfaceType.type, interfaceName, interfaceType.fields); + } + } + + for (const auto& objectType : _objectTypes) + { + validateTransitiveInterfaces(objectType.type, objectType.interfaces); + + for (auto interfaceName : objectType.interfaces) + { + validateInterfaceFields(objectType.type, interfaceName, objectType.fields); + } + } +} + void SchemaLoader::visitDefinition(const peg::ast_node& definition) { if (definition.is_type()) @@ -621,6 +508,21 @@ void SchemaLoader::visitDefinition(const peg::ast_node& definition) void SchemaLoader::visitSchemaDefinition(const peg::ast_node& schemaDefinition) { + std::string_view description; + + peg::on_first_child(schemaDefinition, + [&description](const peg::ast_node& child) { + if (!child.children.empty()) + { + description = child.children.front()->unescaped_view(); + } + }); + + if (_schemaDescription.empty()) + { + _schemaDescription = description; + } + peg::for_each_child(schemaDefinition, [this](const peg::ast_node& child) { const auto operation(child.children.front()->string_view()); @@ -649,8 +551,12 @@ void SchemaLoader::visitObjectTypeDefinition(const peg::ast_node& objectTypeDefi std::string_view description; peg::on_first_child(objectTypeDefinition, - [&name](const peg::ast_node& child) { + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } }); peg::on_first_child(objectTypeDefinition, @@ -676,9 +582,14 @@ void SchemaLoader::visitObjectTypeExtension(const peg::ast_node& objectTypeExten { std::string_view name; - peg::on_first_child(objectTypeExtension, [&name](const peg::ast_node& child) { - name = child.string_view(); - }); + peg::on_first_child(objectTypeExtension, + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { + name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } + }); const auto itrType = _objectNames.find(name); @@ -701,6 +612,18 @@ void SchemaLoader::visitObjectTypeExtension(const peg::ast_node& objectTypeExten objectType.fields.push_back(std::move(field)); } }); + + if (!_isIntrospection) + { + for (const auto& field : objectType.fields) + { + blockReservedName(field.name, field.position); + for (const auto& argument : field.arguments) + { + blockReservedName(argument.name, argument.position); + } + } + } } } @@ -710,8 +633,12 @@ void SchemaLoader::visitInterfaceTypeDefinition(const peg::ast_node& interfaceTy std::string_view description; peg::on_first_child(interfaceTypeDefinition, - [&name](const peg::ast_node& child) { + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } }); peg::on_first_child(interfaceTypeDefinition, @@ -728,7 +655,7 @@ void SchemaLoader::visitInterfaceTypeDefinition(const peg::ast_node& interfaceTy auto cppName = getSafeCppName(name); - _interfaceTypes.push_back({ name, cppName, {}, description }); + _interfaceTypes.push_back({ name, cppName, {}, {}, description }); visitInterfaceTypeExtension(interfaceTypeDefinition); } @@ -738,8 +665,12 @@ void SchemaLoader::visitInterfaceTypeExtension(const peg::ast_node& interfaceTyp std::string_view name; peg::on_first_child(interfaceTypeExtension, - [&name](const peg::ast_node& child) { + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } }); const auto itrType = _interfaceNames.find(name); @@ -748,6 +679,11 @@ void SchemaLoader::visitInterfaceTypeExtension(const peg::ast_node& interfaceTyp { auto& interfaceType = _interfaceTypes[itrType->second]; + peg::for_each_child(interfaceTypeExtension, + [&interfaceType](const peg::ast_node& child) { + interfaceType.interfaces.push_back(child.string_view()); + }); + peg::on_first_child(interfaceTypeExtension, [&interfaceType](const peg::ast_node& child) { auto fields = getOutputFields(child.children); @@ -758,6 +694,18 @@ void SchemaLoader::visitInterfaceTypeExtension(const peg::ast_node& interfaceTyp interfaceType.fields.push_back(std::move(field)); } }); + + if (!_isIntrospection) + { + for (const auto& field : interfaceType.fields) + { + blockReservedName(field.name, field.position); + for (const auto& argument : field.arguments) + { + blockReservedName(argument.name, argument.position); + } + } + } } } @@ -767,8 +715,12 @@ void SchemaLoader::visitInputObjectTypeDefinition(const peg::ast_node& inputObje std::string_view description; peg::on_first_child(inputObjectTypeDefinition, - [&name](const peg::ast_node& child) { + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } }); peg::on_first_child(inputObjectTypeDefinition, @@ -795,8 +747,12 @@ void SchemaLoader::visitInputObjectTypeExtension(const peg::ast_node& inputObjec std::string_view name; peg::on_first_child(inputObjectTypeExtension, - [&name](const peg::ast_node& child) { + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } }); const auto itrType = _inputNames.find(name); @@ -815,6 +771,14 @@ void SchemaLoader::visitInputObjectTypeExtension(const peg::ast_node& inputObjec inputType.fields.push_back(std::move(field)); } }); + + if (!_isIntrospection) + { + for (const auto& field : inputType.fields) + { + blockReservedName(field.name, field.position); + } + } } } @@ -823,9 +787,14 @@ void SchemaLoader::visitEnumTypeDefinition(const peg::ast_node& enumTypeDefiniti std::string_view name; std::string_view description; - peg::on_first_child(enumTypeDefinition, [&name](const peg::ast_node& child) { - name = child.string_view(); - }); + peg::on_first_child(enumTypeDefinition, + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { + name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } + }); peg::on_first_child(enumTypeDefinition, [&description](const peg::ast_node& child) { @@ -850,9 +819,14 @@ void SchemaLoader::visitEnumTypeExtension(const peg::ast_node& enumTypeExtension { std::string_view name; - peg::on_first_child(enumTypeExtension, [&name](const peg::ast_node& child) { - name = child.string_view(); - }); + peg::on_first_child(enumTypeExtension, + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { + name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } + }); const auto itrType = _enumNames.find(name); @@ -887,7 +861,7 @@ void SchemaLoader::visitEnumTypeExtension(const peg::ast_node& enumTypeExtension directiveName = name.string_view(); }); - if (directiveName == "deprecated") + if (directiveName == "deprecated"sv) { std::string_view reason; @@ -902,7 +876,7 @@ void SchemaLoader::visitEnumTypeExtension(const peg::ast_node& enumTypeExtension argumentName = name.string_view(); }); - if (argumentName == "reason") + if (argumentName == "reason"sv) { peg::on_first_child(argument, [&value](const peg::ast_node& argumentValue) { @@ -928,8 +902,12 @@ void SchemaLoader::visitScalarTypeDefinition(const peg::ast_node& scalarTypeDefi std::string_view description; peg::on_first_child(scalarTypeDefinition, - [&name](const peg::ast_node& child) { + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } }); peg::on_first_child(scalarTypeDefinition, @@ -944,6 +922,70 @@ void SchemaLoader::visitScalarTypeDefinition(const peg::ast_node& scalarTypeDefi _typePositions.emplace(name, scalarTypeDefinition.begin()); _scalarNames[name] = _scalarTypes.size(); _scalarTypes.push_back({ name, description }); + + visitScalarTypeExtension(scalarTypeDefinition); +} + +void SchemaLoader::visitScalarTypeExtension(const peg::ast_node& scalarTypeExtension) +{ + std::string_view name; + + peg::on_first_child(scalarTypeExtension, + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { + name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } + }); + + const auto itrType = _scalarNames.find(name); + + if (itrType != _scalarNames.cend()) + { + auto& scalarType = _scalarTypes[itrType->second]; + + peg::on_first_child(scalarTypeExtension, + [&scalarType](const peg::ast_node& directives) { + peg::for_each_child(directives, + [&scalarType](const peg::ast_node& directive) { + std::string_view directiveName; + + peg::on_first_child(directive, + [&directiveName](const peg::ast_node& name) { + directiveName = name.string_view(); + }); + + if (directiveName == "specifiedBy"sv) + { + std::string_view specifiedByURL; + + peg::on_first_child(directive, + [&specifiedByURL](const peg::ast_node& arguments) { + peg::on_first_child(arguments, + [&specifiedByURL](const peg::ast_node& argument) { + std::string_view argumentName; + + peg::on_first_child(argument, + [&argumentName](const peg::ast_node& name) { + argumentName = name.string_view(); + }); + + if (argumentName == "url"sv) + { + peg::on_first_child(argument, + [&specifiedByURL](const peg::ast_node& url) { + specifiedByURL = url.unescaped_view(); + }); + } + }); + }); + + scalarType.specifiedByURL = std::move(specifiedByURL); + } + }); + }); + } } void SchemaLoader::visitUnionTypeDefinition(const peg::ast_node& unionTypeDefinition) @@ -951,9 +993,14 @@ void SchemaLoader::visitUnionTypeDefinition(const peg::ast_node& unionTypeDefini std::string_view name; std::string_view description; - peg::on_first_child(unionTypeDefinition, [&name](const peg::ast_node& child) { - name = child.string_view(); - }); + peg::on_first_child(unionTypeDefinition, + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { + name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } + }); peg::on_first_child(unionTypeDefinition, [&description](const peg::ast_node& child) { @@ -978,9 +1025,14 @@ void SchemaLoader::visitUnionTypeExtension(const peg::ast_node& unionTypeExtensi { std::string_view name; - peg::on_first_child(unionTypeExtension, [&name](const peg::ast_node& child) { - name = child.string_view(); - }); + peg::on_first_child(unionTypeExtension, + [isIntrospection = _isIntrospection, &name](const peg::ast_node& child) { + name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(name, child.begin()); + } + }); const auto itrType = _unionNames.find(name); @@ -1000,8 +1052,12 @@ void SchemaLoader::visitDirectiveDefinition(const peg::ast_node& directiveDefini Directive directive; peg::on_first_child(directiveDefinition, - [&directive](const peg::ast_node& child) { + [isIntrospection = _isIntrospection, &directive](const peg::ast_node& child) { directive.name = child.string_view(); + if (!isIntrospection) + { + blockReservedName(directive.name, child.begin()); + } }); peg::on_first_child(directiveDefinition, @@ -1012,18 +1068,27 @@ void SchemaLoader::visitDirectiveDefinition(const peg::ast_node& directiveDefini } }); + peg::on_first_child(directiveDefinition, + [&directive](const peg::ast_node& child) { + directive.isRepeatable = true; + }); + peg::for_each_child(directiveDefinition, [&directive](const peg::ast_node& child) { directive.locations.push_back(child.string_view()); }); peg::on_first_child(directiveDefinition, - [&directive](const peg::ast_node& child) { + [isIntrospection = _isIntrospection, &directive](const peg::ast_node& child) { auto fields = getInputFields(child.children); directive.arguments.reserve(directive.arguments.size() + fields.size()); for (auto& field : fields) { + if (!isIntrospection) + { + blockReservedName(field.name, field.position); + } directive.arguments.push_back(std::move(field)); } }); @@ -1067,6 +1132,148 @@ std::string_view SchemaLoader::getSafeCppName(std::string_view type) noexcept return (safeNames.cend() == itr) ? type : itr->second->second; } +void SchemaLoader::blockReservedName( + std::string_view name, std::optional position) +{ + // https://spec.graphql.org/October2021/#sec-Names.Reserved-Names + if (name.size() > 1 && name.substr(0, 2) == R"gql(__)gql"sv) + { + std::ostringstream error; + + error << "Names starting with __ are reserved: " << name; + + if (position) + { + error << " line: " << position->line << " column: " << position->column; + } + + throw std::runtime_error(error.str()); + } +} + +const InterfaceType& SchemaLoader::findInterfaceType( + std::string_view typeName, std::string_view interfaceName) const +{ + const auto itrType = _interfaceNames.find(interfaceName); + + if (itrType == _interfaceNames.cend()) + { + std::ostringstream error; + const auto itrPosition = _typePositions.find(typeName); + + error << "Unknown interface: " << interfaceName << " implemented by: " << typeName; + + if (itrPosition != _typePositions.cend()) + { + error << " line: " << itrPosition->second.line + << " column: " << itrPosition->second.column; + } + + throw std::runtime_error(error.str()); + } + + return _interfaceTypes[itrType->second]; +} + +void SchemaLoader::validateInterfaceFields(std::string_view typeName, + std::string_view interfaceName, const OutputFieldList& typeFields) const +{ + const auto& interfaceType = findInterfaceType(typeName, interfaceName); + std::set unimplemented; + + for (const auto& entry : interfaceType.fields) + { + unimplemented.insert(entry.name); + } + + for (const auto& entry : typeFields) + { + unimplemented.erase(entry.name); + } + + if (!unimplemented.empty()) + { + std::ostringstream error; + const auto itrPosition = _typePositions.find(typeName); + + error << "Missing interface fields type: " << typeName + << " interface: " << interfaceType.type; + + if (itrPosition != _typePositions.cend()) + { + error << " line: " << itrPosition->second.line + << " column: " << itrPosition->second.column; + } + + for (auto fieldName : unimplemented) + { + error << " field: " << fieldName; + } + + throw std::runtime_error(error.str()); + } +} + +void SchemaLoader::validateTransitiveInterfaces( + std::string_view typeName, const std::vector& interfaces) const +{ + std::set unimplemented; + + for (auto entry : interfaces) + { + const auto& interfaceType = findInterfaceType(typeName, entry); + + unimplemented.insert(entry); + + for (auto interfaceName : interfaceType.interfaces) + { + unimplemented.insert(interfaceName); + } + } + + if (unimplemented.find(typeName) != unimplemented.cend()) + { + std::ostringstream error; + const auto itrPosition = _typePositions.find(typeName); + + error << "Interface cycle interface: " << typeName; + + if (itrPosition != _typePositions.cend()) + { + error << " line: " << itrPosition->second.line + << " column: " << itrPosition->second.column; + } + + throw std::runtime_error(error.str()); + } + + for (auto entry : interfaces) + { + unimplemented.erase(entry); + } + + if (!unimplemented.empty()) + { + std::ostringstream error; + const auto itrPosition = _typePositions.find(typeName); + + error << "Missing transitive interface type: " << typeName; + + if (itrPosition != _typePositions.cend()) + { + error << " line: " << itrPosition->second.line + << " column: " << itrPosition->second.column; + } + + for (auto interfaceName : unimplemented) + { + error << " interface: " << interfaceName; + } + + throw std::runtime_error(error.str()); + } +} + OutputFieldList SchemaLoader::getOutputFields(const peg::ast_node::children_t& fields) { OutputFieldList outputFields; @@ -1107,7 +1314,7 @@ OutputFieldList SchemaLoader::getOutputFields(const peg::ast_node::children_t& f directiveName = name.string_view(); }); - if (directiveName == "deprecated") + if (directiveName == "deprecated"sv) { std::string_view deprecationReason; @@ -1122,7 +1329,7 @@ OutputFieldList SchemaLoader::getOutputFields(const peg::ast_node::children_t& f argumentName = name.string_view(); }); - if (argumentName == "reason") + if (argumentName == "reason"sv) { peg::on_first_child(argument, [&deprecationReason]( @@ -1213,9 +1420,14 @@ bool SchemaLoader::isIntrospection() const noexcept return _isIntrospection; } +std::string_view SchemaLoader::getSchemaDescription() const noexcept +{ + return _schemaDescription; +} + std::string_view SchemaLoader::getFilenamePrefix() const noexcept { - return _customSchema ? _customSchema->filenamePrefix : "Introspection"sv; + return _schemaOptions.filenamePrefix; } std::string_view SchemaLoader::getSchemaNamespace() const noexcept @@ -1392,6 +1604,22 @@ std::string SchemaLoader::getOutputCppType(const OutputField& field) const noexc size_t templateCount = 0; std::ostringstream outputType; + switch (field.fieldType) + { + case OutputFieldType::Object: + case OutputFieldType::Union: + case OutputFieldType::Interface: + // Even if it's non-nullable, we still want to return a shared_ptr for complex types + outputType << R"cpp(service::AwaitableObject<)cpp"; + ++templateCount; + break; + + default: + outputType << R"cpp(service::AwaitableScalar<)cpp"; + ++templateCount; + break; + } + for (auto modifier : field.modifiers) { if (!nonNull) @@ -1445,19 +1673,11 @@ std::string SchemaLoader::getOutputCppType(const OutputField& field) const noexc outputType << getCppType(field.type); break; + case OutputFieldType::Interface: + case OutputFieldType::Union: case OutputFieldType::Object: - if (field.interfaceField) - { - outputType << R"cpp(object::)cpp"; - } - outputType << getSafeCppName(field.type); break; - - case OutputFieldType::Union: - case OutputFieldType::Interface: - outputType << R"cpp(service::Object)cpp"; - break; } for (size_t i = 0; i < templateCount; ++i) diff --git a/src/SyntaxTree.cpp b/src/SyntaxTree.cpp index b323f54c..e7cad6a5 100644 --- a/src/SyntaxTree.cpp +++ b/src/SyntaxTree.cpp @@ -9,9 +9,12 @@ #include #include +#include #include #include +#include #include +#include using namespace std::literals; @@ -47,7 +50,90 @@ std::string_view ast_node::unescaped_view() const { if (!_unescaped) { - if (children.size() > 1) + if (is_type()) + { + // Trim leading and trailing empty lines + const auto isNonEmptyLine = [](const std::unique_ptr& child) noexcept { + return child->is_type(); + }; + const auto itrEndRev = std::make_reverse_iterator( + std::find_if(children.cbegin(), children.cend(), isNonEmptyLine)); + const auto itrRev = std::find_if(children.crbegin(), itrEndRev, isNonEmptyLine); + std::vector>> lines( + std::distance(itrRev, itrEndRev)); + + std::transform(itrRev, + itrEndRev, + lines.rbegin(), + [](const std::unique_ptr& child) noexcept { + return (child->is_type() && !child->children.empty() + && child->children.front()->is_type() + && child->children.back()->is_type()) + ? std::make_optional(std::make_pair(child->children.front()->string_view(), + child->children.back()->unescaped_view())) + : std::nullopt; + }); + + // Calculate the common indent + const auto commonIndent = std::accumulate(lines.cbegin(), + lines.cend(), + std::optional {}, + [](auto value, const auto& line) noexcept { + if (line) + { + const auto indent = line->first.size(); + + if (!value || indent < *value) + { + value = indent; + } + } + + return value; + }); + + const auto trimIndent = commonIndent ? *commonIndent : 0; + std::string joined; + + if (!lines.empty()) + { + joined.reserve(std::accumulate(lines.cbegin(), + lines.cend(), + size_t {}, + [trimIndent](auto value, const auto& line) noexcept { + if (line) + { + value += line->first.size() - trimIndent; + value += line->second.size(); + } + + return value; + }) + + lines.size() - 1); + + bool firstLine = true; + + for (const auto& line : lines) + { + if (!firstLine) + { + joined.append(1, '\n'); + } + + if (line) + { + joined.append(line->first.substr(trimIndent)); + joined.append(line->second); + } + + firstLine = false; + } + } + + const_cast(this)->_unescaped = + std::make_unique(std::move(joined)); + } + else if (children.size() > 1) { std::string joined; @@ -224,6 +310,26 @@ struct ast_selector : std::true_type } }; +template <> +struct ast_selector : std::true_type +{ +}; + +template <> +struct ast_selector : std::true_type +{ +}; + +template <> +struct ast_selector : std::true_type +{ +}; + +template <> +struct ast_selector : std::true_type +{ +}; + template <> struct ast_selector : std::true_type { @@ -483,6 +589,11 @@ struct schema_selector : std::true_type { }; +template <> +struct schema_selector : std::true_type +{ +}; + template <> struct schema_selector : std::true_type { @@ -573,164 +684,164 @@ const std::string ast_control::error_message = "Expected \"\" template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#Variable"; + "Expected https://spec.graphql.org/October2021/#Variable"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#EscapedUnicode"; + "Expected https://spec.graphql.org/October2021/#EscapedUnicode"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#EscapedCharacter"; + "Expected https://spec.graphql.org/October2021/#EscapedCharacter"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#StringCharacter"; + "Expected https://spec.graphql.org/October2021/#StringCharacter"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#BlockStringCharacter"; + "Expected https://spec.graphql.org/October2021/#BlockStringCharacter"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#FractionalPart"; + "Expected https://spec.graphql.org/October2021/#FractionalPart"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#ExponentPart"; + "Expected https://spec.graphql.org/October2021/#ExponentPart"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#Argument"; + "Expected https://spec.graphql.org/October2021/#Argument"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#Arguments"; + "Expected https://spec.graphql.org/October2021/#Arguments"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#ListValue"; + "Expected https://spec.graphql.org/October2021/#ListValue"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#ObjectField"; + "Expected https://spec.graphql.org/October2021/#ObjectField"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#ObjectValue"; + "Expected https://spec.graphql.org/October2021/#ObjectValue"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#Value"; + "Expected https://spec.graphql.org/October2021/#Value"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#DefaultValue"; + "Expected https://spec.graphql.org/October2021/#DefaultValue"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#ListType"; + "Expected https://spec.graphql.org/October2021/#ListType"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#Type"; + "Expected https://spec.graphql.org/October2021/#Type"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#VariableDefinition"; + "Expected https://spec.graphql.org/October2021/#VariableDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#VariableDefinitions"; + "Expected https://spec.graphql.org/October2021/#VariableDefinitions"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#Directive"; + "Expected https://spec.graphql.org/October2021/#Directive"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#Field"; + "Expected https://spec.graphql.org/October2021/#Field"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#TypeCondition"; + "Expected https://spec.graphql.org/October2021/#TypeCondition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#FragmentSpread or " - "http://spec.graphql.org/June2018/#InlineFragment"; + "Expected https://spec.graphql.org/October2021/#FragmentSpread or " + "https://spec.graphql.org/October2021/#InlineFragment"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#SelectionSet"; + "Expected https://spec.graphql.org/October2021/#SelectionSet"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#OperationDefinition"; + "Expected https://spec.graphql.org/October2021/#OperationDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#FragmentDefinition"; + "Expected https://spec.graphql.org/October2021/#FragmentDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#RootOperationTypeDefinition"; + "Expected https://spec.graphql.org/October2021/#RootOperationTypeDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#SchemaDefinition"; + "Expected https://spec.graphql.org/October2021/#SchemaDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#ScalarTypeDefinition"; + "Expected https://spec.graphql.org/October2021/#ScalarTypeDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#ArgumentsDefinition"; + "Expected https://spec.graphql.org/October2021/#ArgumentsDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#FieldDefinition"; + "Expected https://spec.graphql.org/October2021/#FieldDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#FieldsDefinition"; + "Expected https://spec.graphql.org/October2021/#FieldsDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#ImplementsInterfaces"; + "Expected https://spec.graphql.org/October2021/#ImplementsInterfaces"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#ObjectTypeDefinition"; + "Expected https://spec.graphql.org/October2021/#ObjectTypeDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#InterfaceTypeDefinition"; + "Expected https://spec.graphql.org/October2021/#InterfaceTypeDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#UnionMemberTypes"; + "Expected https://spec.graphql.org/October2021/#UnionMemberTypes"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#UnionTypeDefinition"; + "Expected https://spec.graphql.org/October2021/#UnionTypeDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#EnumValueDefinition"; + "Expected https://spec.graphql.org/October2021/#EnumValueDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#EnumValuesDefinition"; + "Expected https://spec.graphql.org/October2021/#EnumValuesDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#EnumTypeDefinition"; + "Expected https://spec.graphql.org/October2021/#EnumTypeDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#InputValueDefinition"; + "Expected https://spec.graphql.org/October2021/#InputValueDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#InputFieldsDefinition"; + "Expected https://spec.graphql.org/October2021/#InputFieldsDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#InputObjectTypeDefinition"; + "Expected https://spec.graphql.org/October2021/#InputObjectTypeDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#DirectiveDefinition"; + "Expected https://spec.graphql.org/October2021/#DirectiveDefinition"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#SchemaExtension"; + "Expected https://spec.graphql.org/October2021/#SchemaExtension"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#ScalarTypeExtension"; + "Expected https://spec.graphql.org/October2021/#ScalarTypeExtension"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#ObjectTypeExtension"; + "Expected https://spec.graphql.org/October2021/#ObjectTypeExtension"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#InterfaceTypeExtension"; + "Expected https://spec.graphql.org/October2021/#InterfaceTypeExtension"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#UnionTypeExtension"; + "Expected https://spec.graphql.org/October2021/#UnionTypeExtension"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#EnumTypeExtension"; + "Expected https://spec.graphql.org/October2021/#EnumTypeExtension"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#InputObjectTypeExtension"; + "Expected https://spec.graphql.org/October2021/#InputObjectTypeExtension"; template <> const std::string ast_control::error_message = - "Expected http://spec.graphql.org/June2018/#Document"; + "Expected https://spec.graphql.org/October2021/#Document"; template <> const std::string ast_control::error_message = - "Expected executable http://spec.graphql.org/June2018/#Document"; + "Expected executable https://spec.graphql.org/October2021/#Document"; template <> const std::string ast_control::error_message = - "Expected schema type http://spec.graphql.org/June2018/#Document"; + "Expected schema type https://spec.graphql.org/October2021/#Document"; ast parseSchemaString(std::string_view input) { diff --git a/src/Validation.cpp b/src/Validation.cpp index 23e4731e..79197c74 100644 --- a/src/Validation.cpp +++ b/src/Validation.cpp @@ -64,12 +64,12 @@ ValidateArgumentValue::ValidateArgumentValue(ValidateArgumentVariable&& value) { } -ValidateArgumentValue::ValidateArgumentValue(response::IntType value) +ValidateArgumentValue::ValidateArgumentValue(int value) : data(value) { } -ValidateArgumentValue::ValidateArgumentValue(response::FloatType value) +ValidateArgumentValue::ValidateArgumentValue(double value) : data(value) { } @@ -79,7 +79,7 @@ ValidateArgumentValue::ValidateArgumentValue(std::string_view value) { } -ValidateArgumentValue::ValidateArgumentValue(response::BooleanType value) +ValidateArgumentValue::ValidateArgumentValue(bool value) : data(value) { } @@ -162,7 +162,7 @@ void ValidateArgumentValueVisitor::visitVariable(const peg::ast_node& variable) void ValidateArgumentValueVisitor::visitIntValue(const peg::ast_node& intValue) { - response::IntType value { std::atoi(intValue.string().c_str()) }; + int value { std::atoi(intValue.string().c_str()) }; auto position = intValue.begin(); _argumentValue.value = std::make_unique(value); @@ -171,7 +171,7 @@ void ValidateArgumentValueVisitor::visitIntValue(const peg::ast_node& intValue) void ValidateArgumentValueVisitor::visitFloatValue(const peg::ast_node& floatValue) { - response::FloatType value { std::atof(floatValue.string().c_str()) }; + double value { std::atof(floatValue.string().c_str()) }; auto position = floatValue.begin(); _argumentValue.value = std::make_unique(value); @@ -189,7 +189,7 @@ void ValidateArgumentValueVisitor::visitStringValue(const peg::ast_node& stringV void ValidateArgumentValueVisitor::visitBooleanValue(const peg::ast_node& booleanValue) { - response::BooleanType value { booleanValue.is_type() }; + bool value { booleanValue.is_type() }; auto position = booleanValue.begin(); _argumentValue.value = std::make_unique(value); @@ -243,7 +243,7 @@ void ValidateArgumentValueVisitor::visitObjectValue(const peg::ast_node& objectV if (value.values.find(name) != value.values.end()) { - // http://spec.graphql.org/June2018/#sec-Input-Object-Field-Uniqueness + // https://spec.graphql.org/October2021/#sec-Input-Object-Field-Uniqueness auto position = field->begin(); std::ostringstream message; @@ -358,7 +358,7 @@ ValidateType ValidateVariableTypeVisitor::getType() return result; } -ValidateExecutableVisitor::ValidateExecutableVisitor(const std::shared_ptr& schema) +ValidateExecutableVisitor::ValidateExecutableVisitor(std::shared_ptr schema) : _schema(schema) { const auto& queryType = _schema->queryType(); @@ -403,7 +403,15 @@ ValidateExecutableVisitor::ValidateExecutableVisitor(const std::shared_ptrpossibleTypes(); - matchingTypes.reserve(possibleTypes.size()); + if (kind == introspection::TypeKind::INTERFACE) + { + matchingTypes.reserve(possibleTypes.size() + 1); + matchingTypes.emplace(name); + } + else + { + matchingTypes.reserve(possibleTypes.size()); + } for (const auto& possibleType : possibleTypes) { @@ -460,6 +468,8 @@ ValidateExecutableVisitor::ValidateExecutableVisitor(const std::shared_ptrargs(); ValidateDirective validateDirective; + validateDirective.isRepeatable = directive->isRepeatable(); + for (const auto location : locations) { validateDirective.locations.emplace(location); @@ -481,7 +491,7 @@ void ValidateExecutableVisitor::visit(const peg::ast_node& root) if (!inserted.second) { - // http://spec.graphql.org/June2018/#sec-Fragment-Name-Uniqueness + // https://spec.graphql.org/October2021/#sec-Fragment-Name-Uniqueness auto position = fragmentDefinition.begin(); std::ostringstream error; @@ -505,7 +515,7 @@ void ValidateExecutableVisitor::visit(const peg::ast_node& root) if (!inserted.second) { - // http://spec.graphql.org/June2018/#sec-Operation-Name-Uniqueness + // https://spec.graphql.org/October2021/#sec-Operation-Name-Uniqueness auto position = operationDefinition.begin(); std::ostringstream error; @@ -526,7 +536,7 @@ void ValidateExecutableVisitor::visit(const peg::ast_node& root) if (itr != _operationDefinitions.end()) { - // http://spec.graphql.org/June2018/#sec-Lone-Anonymous-Operation + // https://spec.graphql.org/October2021/#sec-Lone-Anonymous-Operation auto position = itr->second.get().begin(); _errors.push_back( @@ -547,7 +557,7 @@ void ValidateExecutableVisitor::visit(const peg::ast_node& root) } else { - // http://spec.graphql.org/June2018/#sec-Executable-Definitions + // https://spec.graphql.org/October2021/#sec-Executable-Definitions auto position = child->begin(); _errors.push_back({ "Unexpected type definition", { position.line, position.column } }); @@ -556,7 +566,7 @@ void ValidateExecutableVisitor::visit(const peg::ast_node& root) if (!_fragmentDefinitions.empty()) { - // http://spec.graphql.org/June2018/#sec-Fragments-Must-Be-Used + // https://spec.graphql.org/October2021/#sec-Fragments-Must-Be-Used const size_t originalSize = _errors.size(); auto unreferencedFragments = std::move(_fragmentDefinitions); @@ -607,8 +617,8 @@ void ValidateExecutableVisitor::visitFragmentDefinition(const peg::ast_node& fra if (itrType == _types.end() || isScalarType(itrType->second->get().kind())) { - // http://spec.graphql.org/June2018/#sec-Fragment-Spread-Type-Existence - // http://spec.graphql.org/June2018/#sec-Fragments-On-Composite-Types + // https://spec.graphql.org/October2021/#sec-Fragment-Spread-Type-Existence + // https://spec.graphql.org/October2021/#sec-Fragments-On-Composite-Types auto position = typeCondition->begin(); std::ostringstream message; @@ -662,7 +672,7 @@ void ValidateExecutableVisitor::visitOperationDefinition(const peg::ast_node& op if (_operationVariables->find(variableName) != _operationVariables->end()) { - // http://spec.graphql.org/June2018/#sec-Variable-Uniqueness + // https://spec.graphql.org/October2021/#sec-Variable-Uniqueness auto position = child->begin(); std::ostringstream message; @@ -688,7 +698,7 @@ void ValidateExecutableVisitor::visitOperationDefinition(const peg::ast_node& op if (!visitor.isInputType()) { - // http://spec.graphql.org/June2018/#sec-Variables-Are-Input-Types + // https://spec.graphql.org/October2021/#sec-Variables-Are-Input-Types auto position = child->begin(); std::ostringstream message; @@ -717,7 +727,7 @@ void ValidateExecutableVisitor::visitOperationDefinition(const peg::ast_node& op if (!validateInputValue(false, argument, variableArgument.type)) { - // http://spec.graphql.org/June2018/#sec-Values-of-Correct-Type + // https://spec.graphql.org/October2021/#sec-Values-of-Correct-Type auto position = child->begin(); std::ostringstream message; @@ -773,26 +783,46 @@ void ValidateExecutableVisitor::visitOperationDefinition(const peg::ast_node& op } _scopedType = itrType->second; + _introspectionFieldCount = 0; _fieldCount = 0; const auto& selection = *operationDefinition.children.back(); visitSelection(selection); - if (_fieldCount > 1 && operationType == strSubscription) + if (operationType == strSubscription) { - // http://spec.graphql.org/June2018/#sec-Single-root-field - auto position = operationDefinition.begin(); - std::ostringstream error; + if (_fieldCount > 1) + { + // https://spec.graphql.org/October2021/#sec-Single-root-field + auto position = operationDefinition.begin(); + std::ostringstream error; - error << "Subscription with more than one root field"; + error << "Subscription with more than one root field"; - if (!operationName.empty()) - { - error << " name: " << operationName; + if (!operationName.empty()) + { + error << " name: " << operationName; + } + + _errors.push_back({ error.str(), { position.line, position.column } }); } - _errors.push_back({ error.str(), { position.line, position.column } }); + if (_introspectionFieldCount != 0) + { + // https://spec.graphql.org/October2021/#sec-Single-root-field + auto position = operationDefinition.begin(); + std::ostringstream error; + + error << "Subscription with Introspection root field"; + + if (!operationName.empty()) + { + error << " name: " << operationName; + } + + _errors.push_back({ error.str(), { position.line, position.column } }); + } } _scopedType.reset(); @@ -803,7 +833,7 @@ void ValidateExecutableVisitor::visitOperationDefinition(const peg::ast_node& op { if (_referencedVariables.find(variable.first) == _referencedVariables.end()) { - // http://spec.graphql.org/June2018/#sec-All-Variables-Used + // https://spec.graphql.org/October2021/#sec-All-Variables-Used auto position = variable.second.get().begin(); std::ostringstream error; @@ -918,7 +948,7 @@ bool ValidateExecutableVisitor::validateInputValue( if (itrVariable == _operationVariables->end()) { - // http://spec.graphql.org/June2018/#sec-All-Variable-Uses-Defined + // https://spec.graphql.org/October2021/#sec-All-Variable-Uses-Defined std::ostringstream message; message << "Undefined variable name: " << variable.name; @@ -1046,7 +1076,7 @@ bool ValidateExecutableVisitor::validateInputValue( if (itrField == itrFields->second.end()) { - // http://spec.graphql.org/June2018/#sec-Input-Object-Field-Names + // https://spec.graphql.org/October2021/#sec-Input-Object-Field-Names std::ostringstream message; message << "Undefined Input Object field type: " << name @@ -1097,7 +1127,7 @@ bool ValidateExecutableVisitor::validateInputValue( if (fieldKind == introspection::TypeKind::NON_NULL) { - // http://spec.graphql.org/June2018/#sec-Input-Object-Required-Fields + // https://spec.graphql.org/October2021/#sec-Input-Object-Required-Fields std::ostringstream message; message << "Missing Input Object field type: " << name @@ -1160,7 +1190,7 @@ bool ValidateExecutableVisitor::validateInputValue( if (name == R"gql(Int)gql"sv) { - if (!std::holds_alternative(argument.value->data)) + if (!std::holds_alternative(argument.value->data)) { _errors.push_back({ "Expected Int value", argument.position }); return false; @@ -1168,8 +1198,8 @@ bool ValidateExecutableVisitor::validateInputValue( } else if (name == R"gql(Float)gql"sv) { - if (!std::holds_alternative(argument.value->data) - && !std::holds_alternative(argument.value->data)) + if (!std::holds_alternative(argument.value->data) + && !std::holds_alternative(argument.value->data)) { _errors.push_back({ "Expected Float value", argument.position }); return false; @@ -1205,7 +1235,7 @@ bool ValidateExecutableVisitor::validateInputValue( } else if (name == R"gql(Boolean)gql"sv) { - if (!std::holds_alternative(argument.value->data)) + if (!std::holds_alternative(argument.value->data)) { _errors.push_back({ "Expected Boolean value", argument.position }); return false; @@ -1272,7 +1302,7 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, { if (!isNonNull) { - // http://spec.graphql.org/June2018/#sec-All-Variable-Usages-are-Allowed + // https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed _errors.push_back({ "Expected Non-Null variable type", position }); return false; } @@ -1293,7 +1323,7 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, { if (variableKind != inputKind) { - // http://spec.graphql.org/June2018/#sec-All-Variable-Usages-are-Allowed + // https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed _errors.push_back({ "Expected List variable type", position }); return false; } @@ -1322,7 +1352,7 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, { if (variableKind != inputKind) { - // http://spec.graphql.org/June2018/#sec-All-Variable-Usages-are-Allowed + // https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed _errors.push_back({ "Expected Input Object variable type", position }); return false; } @@ -1334,7 +1364,7 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, { if (variableKind != inputKind) { - // http://spec.graphql.org/June2018/#sec-All-Variable-Usages-are-Allowed + // https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed _errors.push_back({ "Expected Enum variable type", position }); return false; } @@ -1346,7 +1376,7 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, { if (variableKind != inputKind) { - // http://spec.graphql.org/June2018/#sec-All-Variable-Usages-are-Allowed + // https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed _errors.push_back({ "Expected Scalar variable type", position }); return false; } @@ -1356,7 +1386,7 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, default: { - // http://spec.graphql.org/June2018/#sec-All-Variable-Usages-are-Allowed + // https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed _errors.push_back({ "Unexpected input type", position }); return false; } @@ -1380,7 +1410,7 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, if (variableName != inputName) { - // http://spec.graphql.org/June2018/#sec-All-Variable-Usages-are-Allowed + // https://spec.graphql.org/October2021/#sec-All-Variable-Usages-are-Allowed std::ostringstream message; message << "Incompatible variable type: " << variableName << " name: " << inputName; @@ -1544,7 +1574,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) if (itrType == _typeFields.end()) { - // http://spec.graphql.org/June2018/#sec-Leaf-Field-Selections + // https://spec.graphql.org/October2021/#sec-Leaf-Field-Selections auto position = field.begin(); std::ostringstream message; @@ -1562,7 +1592,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) case introspection::TypeKind::OBJECT: case introspection::TypeKind::INTERFACE: { - // http://spec.graphql.org/June2018/#sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types + // https://spec.graphql.org/October2021/#sec-Field-Selections innerType = getFieldType(itrType->second, name); wrappedType = getWrappedFieldType(itrType->second, name); break; @@ -1572,7 +1602,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) { if (name != R"gql(__typename)gql"sv) { - // http://spec.graphql.org/June2018/#sec-Leaf-Field-Selections + // https://spec.graphql.org/October2021/#sec-Leaf-Field-Selections auto position = field.begin(); std::ostringstream message; @@ -1583,7 +1613,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) return; } - // http://spec.graphql.org/June2018/#sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types + // https://spec.graphql.org/October2021/#sec-Field-Selections innerType = getValidateType(_schema->LookupType("String"sv)); wrappedType = getValidateType( _schema->WrapType(introspection::TypeKind::NON_NULL, getSharedType(innerType))); @@ -1596,7 +1626,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) if (!innerType) { - // http://spec.graphql.org/June2018/#sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types + // https://spec.graphql.org/October2021/#sec-Field-Selections auto position = field.begin(); std::ostringstream message; @@ -1622,7 +1652,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) std::list argumentNames; peg::on_first_child(field, - [this, &name, &validateArguments, &argumentLocations, &argumentNames]( + [this, name, &validateArguments, &argumentLocations, &argumentNames]( const peg::ast_node& child) { for (auto& argument : child.children) { @@ -1631,7 +1661,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) if (validateArguments.find(argumentName) != validateArguments.end()) { - // http://spec.graphql.org/June2018/#sec-Argument-Uniqueness + // https://spec.graphql.org/October2021/#sec-Argument-Uniqueness std::ostringstream message; message << "Conflicting argument type: " << _scopedType->get().name() @@ -1668,7 +1698,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) } else { - // http://spec.graphql.org/June2018/#sec-Field-Selection-Merging + // https://spec.graphql.org/October2021/#sec-Field-Selection-Merging auto position = field.begin(); std::ostringstream message; @@ -1688,7 +1718,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) if (itrArgument == itrField->second.arguments.end()) { - // http://spec.graphql.org/June2018/#sec-Argument-Names + // https://spec.graphql.org/October2021/#sec-Argument-Names std::ostringstream message; message << "Undefined argument type: " << _scopedType->get().name() @@ -1710,7 +1740,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) itrArgument->second, argument.second.type)) { - // http://spec.graphql.org/June2018/#sec-Values-of-Correct-Type + // https://spec.graphql.org/October2021/#sec-Values-of-Correct-Type std::ostringstream message; message << "Incompatible argument type: " << _scopedType->get().name() @@ -1731,7 +1761,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) if (argument.second.type && introspection::TypeKind::NON_NULL == argument.second.type->get().kind()) { - // http://spec.graphql.org/June2018/#sec-Required-Arguments + // https://spec.graphql.org/October2021/#sec-Required-Arguments auto position = field.begin(); std::ostringstream message; @@ -1760,8 +1790,10 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) auto outerType = std::move(_scopedType); auto outerFields = std::move(_selectionFields); auto outerFieldCount = _fieldCount; + auto outerIntrospectionFieldCount = _introspectionFieldCount; _fieldCount = 0; + _introspectionFieldCount = 0; _selectionFields.clear(); _scopedType = std::move(innerType); @@ -1771,12 +1803,13 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) _scopedType = std::move(outerType); _selectionFields = std::move(outerFields); subFieldCount = _fieldCount; + _introspectionFieldCount = outerIntrospectionFieldCount; _fieldCount = outerFieldCount; } if (subFieldCount == 0 && !isScalarType(innerType->get().kind())) { - // http://spec.graphql.org/June2018/#sec-Leaf-Field-Selections + // https://spec.graphql.org/October2021/#sec-Leaf-Field-Selections auto position = field.begin(); std::ostringstream message; @@ -1787,6 +1820,14 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) } ++_fieldCount; + + constexpr auto c_introspectionFieldPrefix = R"gql(__)gql"sv; + + if (name.size() >= c_introspectionFieldPrefix.size() + && name.substr(0, c_introspectionFieldPrefix.size()) == c_introspectionFieldPrefix) + { + ++_introspectionFieldCount; + } } void ValidateExecutableVisitor::visitFragmentSpread(const peg::ast_node& fragmentSpread) @@ -1800,7 +1841,7 @@ void ValidateExecutableVisitor::visitFragmentSpread(const peg::ast_node& fragmen if (itr == _fragmentDefinitions.end()) { - // http://spec.graphql.org/June2018/#sec-Fragment-spread-target-defined + // https://spec.graphql.org/October2021/#sec-Fragment-spread-target-defined auto position = fragmentSpread.begin(); std::ostringstream message; @@ -1814,7 +1855,7 @@ void ValidateExecutableVisitor::visitFragmentSpread(const peg::ast_node& fragmen { if (_fragmentCycles.emplace(name).second) { - // http://spec.graphql.org/June2018/#sec-Fragment-spreads-must-not-form-cycles + // https://spec.graphql.org/October2021/#sec-Fragment-spreads-must-not-form-cycles auto position = fragmentSpread.begin(); std::ostringstream message; @@ -1833,7 +1874,7 @@ void ValidateExecutableVisitor::visitFragmentSpread(const peg::ast_node& fragmen if (itrInner == _types.end() || !matchesScopedType(innerType)) { - // http://spec.graphql.org/June2018/#sec-Fragment-spread-is-possible + // https://spec.graphql.org/October2021/#sec-Fragment-spread-is-possible auto position = fragmentSpread.begin(); std::ostringstream message; @@ -1885,7 +1926,7 @@ void ValidateExecutableVisitor::visitInlineFragment(const peg::ast_node& inlineF if (itrInner == _types.end()) { - // http://spec.graphql.org/June2018/#sec-Fragment-Spread-Type-Existence + // https://spec.graphql.org/October2021/#sec-Fragment-Spread-Type-Existence std::ostringstream message; message << "Undefined target type on inline fragment name: " << innerType; @@ -1898,8 +1939,8 @@ void ValidateExecutableVisitor::visitInlineFragment(const peg::ast_node& inlineF if (isScalarType(fragmentType->get().kind()) || !matchesScopedType(innerType)) { - // http://spec.graphql.org/June2018/#sec-Fragments-On-Composite-Types - // http://spec.graphql.org/June2018/#sec-Fragment-spread-is-possible + // https://spec.graphql.org/October2021/#sec-Fragments-On-Composite-Types + // https://spec.graphql.org/October2021/#sec-Fragment-spread-is-possible std::ostringstream message; message << (isScalarType(fragmentType->get().kind()) @@ -1938,27 +1979,27 @@ void ValidateExecutableVisitor::visitDirectives( directiveName = child.string_view(); }); - if (!uniqueDirectives.emplace(directiveName).second) + const auto itrDirective = _directives.find(directiveName); + + if (itrDirective == _directives.end()) { - // http://spec.graphql.org/June2018/#sec-Directives-Are-Unique-Per-Location + // https://spec.graphql.org/October2021/#sec-Directives-Are-Defined auto position = directive->begin(); std::ostringstream message; - message << "Conflicting directive name: " << directiveName; + message << "Undefined directive name: " << directiveName; _errors.push_back({ message.str(), { position.line, position.column } }); continue; } - auto itrDirective = _directives.find(directiveName); - - if (itrDirective == _directives.end()) + if (!itrDirective->second.isRepeatable && !uniqueDirectives.emplace(directiveName).second) { - // http://spec.graphql.org/June2018/#sec-Directives-Are-Defined + // https://spec.graphql.org/October2021/#sec-Directives-Are-Unique-Per-Location auto position = directive->begin(); std::ostringstream message; - message << "Undefined directive name: " << directiveName; + message << "Conflicting directive name: " << directiveName; _errors.push_back({ message.str(), { position.line, position.column } }); continue; @@ -1966,7 +2007,7 @@ void ValidateExecutableVisitor::visitDirectives( if (itrDirective->second.locations.find(location) == itrDirective->second.locations.end()) { - // http://spec.graphql.org/June2018/#sec-Directives-Are-In-Valid-Locations + // https://spec.graphql.org/October2021/#sec-Directives-Are-In-Valid-Locations auto position = directive->begin(); std::ostringstream message; @@ -2023,7 +2064,7 @@ void ValidateExecutableVisitor::visitDirectives( if (validateArguments.find(argumentName) != validateArguments.end()) { - // http://spec.graphql.org/June2018/#sec-Argument-Uniqueness + // https://spec.graphql.org/October2021/#sec-Argument-Uniqueness std::ostringstream message; message << "Conflicting argument directive: " << directiveName @@ -2047,7 +2088,7 @@ void ValidateExecutableVisitor::visitDirectives( if (itrArgument == itrDirective->second.arguments.end()) { - // http://spec.graphql.org/June2018/#sec-Argument-Names + // https://spec.graphql.org/October2021/#sec-Argument-Names std::ostringstream message; message << "Undefined argument directive: " << directiveName @@ -2069,7 +2110,7 @@ void ValidateExecutableVisitor::visitDirectives( itrArgument->second, argument.second.type)) { - // http://spec.graphql.org/June2018/#sec-Values-of-Correct-Type + // https://spec.graphql.org/October2021/#sec-Values-of-Correct-Type std::ostringstream message; message << "Incompatible argument directive: " << directiveName @@ -2090,7 +2131,7 @@ void ValidateExecutableVisitor::visitDirectives( if (argument.second.type && introspection::TypeKind::NON_NULL == argument.second.type->get().kind()) { - // http://spec.graphql.org/June2018/#sec-Required-Arguments + // https://spec.graphql.org/October2021/#sec-Required-Arguments auto position = directive->begin(); std::ostringstream message; diff --git a/src/introspection/CMakeLists.txt b/src/introspection/CMakeLists.txt new file mode 100644 index 00000000..82b8203d --- /dev/null +++ b/src/introspection/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +cmake_minimum_required(VERSION 3.15) + +# Normally this would be handled by find_package(cppgraphqlgen CONFIG). +include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/cppgraphqlgen-functions.cmake) + +if(GRAPHQL_UPDATE_SAMPLES) + update_graphql_schema_files(introspection schema.introspection.graphql Introspection introspection --introspection) + + file(GLOB PRIVATE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) + add_custom_command( + OUTPUT copied_introspection_schema_headers + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PRIVATE_HEADERS} ${CMAKE_CURRENT_SOURCE_DIR}/../../include/graphqlservice/introspection/ + COMMAND ${CMAKE_COMMAND} -E touch copied_introspection_schema_headers + DEPENDS ${PRIVATE_HEADERS} ${CMAKE_CURRENT_SOURCE_DIR}/introspection_schema_files + COMMENT "Updating IntrospectionSchema headers") + + add_custom_target(copy_introspection_schema_headers ALL + DEPENDS copied_introspection_schema_headers) +endif() + +file(GLOB PUBLIC_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../../include/graphqlservice/introspection/*.h) +install(FILES ${PUBLIC_HEADERS} + CONFIGURATIONS ${GRAPHQL_INSTALL_CONFIGURATIONS} + DESTINATION ${GRAPHQL_INSTALL_INCLUDE_DIR}/graphqlservice/introspection) diff --git a/src/introspection/DirectiveObject.cpp b/src/introspection/DirectiveObject.cpp new file mode 100644 index 00000000..0c58c0a0 --- /dev/null +++ b/src/introspection/DirectiveObject.cpp @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "DirectiveObject.h" +#include "InputValueObject.h" + +#include "graphqlservice/internal/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::introspection { +namespace object { + +Directive::Directive(std::shared_ptr pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::make_unique>(std::move(pimpl)) } +{ +} + +Directive::~Directive() +{ + // This is empty, but explicitly defined here so that it can access the un-exported destructor + // of the implementation type. +} + +service::TypeNames Directive::getTypeNames() const noexcept +{ + return { + R"gql(__Directive)gql"sv + }; +} + +service::ResolverMap Directive::getResolvers() const noexcept +{ + return { + { R"gql(args)gql"sv, [this](service::ResolverParams&& params) { return resolveArgs(std::move(params)); } }, + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(locations)gql"sv, [this](service::ResolverParams&& params) { return resolveLocations(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(description)gql"sv, [this](service::ResolverParams&& params) { return resolveDescription(std::move(params)); } }, + { R"gql(isRepeatable)gql"sv, [this](service::ResolverParams&& params) { return resolveIsRepeatable(std::move(params)); } } + }; +} + +service::AwaitableResolver Directive::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getName(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Directive::resolveDescription(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getDescription(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Directive::resolveLocations(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getLocations(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Directive::resolveArgs(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getArgs(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Directive::resolveIsRepeatable(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getIsRepeatable(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Directive::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(__Directive)gql" }, std::move(params)); +} + +} // namespace object + +void AddDirectiveDetails(const std::shared_ptr& typeDirective, const std::shared_ptr& schema) +{ + typeDirective->AddFields({ + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(locations)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__DirectiveLocation)gql"sv))))), + schema::Field::Make(R"gql(args)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__InputValue)gql"sv))))), + schema::Field::Make(R"gql(isRepeatable)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))) + }); +} + +} // namespace graphql::introspection diff --git a/src/introspection/DirectiveObject.h b/src/introspection/DirectiveObject.h new file mode 100644 index 00000000..22b77759 --- /dev/null +++ b/src/introspection/DirectiveObject.h @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef DIRECTIVEOBJECT_H +#define DIRECTIVEOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class Directive + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveLocations(service::ResolverParams&& params) const; + service::AwaitableResolver resolveArgs(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIsRepeatable(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar getName() const = 0; + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableScalar> getLocations() const = 0; + virtual service::AwaitableObject>> getArgs() const = 0; + virtual service::AwaitableScalar getIsRepeatable() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName() const final + { + return { _pimpl->getName() }; + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableScalar> getLocations() const final + { + return { _pimpl->getLocations() }; + } + + service::AwaitableObject>> getArgs() const final + { + return { _pimpl->getArgs() }; + } + + service::AwaitableScalar getIsRepeatable() const final + { + return { _pimpl->getIsRepeatable() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT Directive(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~Directive(); +}; + +} // namespace graphql::introspection::object + +#endif // DIRECTIVEOBJECT_H diff --git a/src/introspection/EnumValueObject.cpp b/src/introspection/EnumValueObject.cpp new file mode 100644 index 00000000..d571ec2b --- /dev/null +++ b/src/introspection/EnumValueObject.cpp @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "EnumValueObject.h" + +#include "graphqlservice/internal/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::introspection { +namespace object { + +EnumValue::EnumValue(std::shared_ptr pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::make_unique>(std::move(pimpl)) } +{ +} + +EnumValue::~EnumValue() +{ + // This is empty, but explicitly defined here so that it can access the un-exported destructor + // of the implementation type. +} + +service::TypeNames EnumValue::getTypeNames() const noexcept +{ + return { + R"gql(__EnumValue)gql"sv + }; +} + +service::ResolverMap EnumValue::getResolvers() const noexcept +{ + return { + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(description)gql"sv, [this](service::ResolverParams&& params) { return resolveDescription(std::move(params)); } }, + { R"gql(isDeprecated)gql"sv, [this](service::ResolverParams&& params) { return resolveIsDeprecated(std::move(params)); } }, + { R"gql(deprecationReason)gql"sv, [this](service::ResolverParams&& params) { return resolveDeprecationReason(std::move(params)); } } + }; +} + +service::AwaitableResolver EnumValue::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getName(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver EnumValue::resolveDescription(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getDescription(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver EnumValue::resolveIsDeprecated(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getIsDeprecated(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver EnumValue::resolveDeprecationReason(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getDeprecationReason(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver EnumValue::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(__EnumValue)gql" }, std::move(params)); +} + +} // namespace object + +void AddEnumValueDetails(const std::shared_ptr& typeEnumValue, const std::shared_ptr& schema) +{ + typeEnumValue->AddFields({ + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(isDeprecated)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))), + schema::Field::Make(R"gql(deprecationReason)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::introspection diff --git a/src/introspection/EnumValueObject.h b/src/introspection/EnumValueObject.h new file mode 100644 index 00000000..390565c7 --- /dev/null +++ b/src/introspection/EnumValueObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef ENUMVALUEOBJECT_H +#define ENUMVALUEOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class EnumValue + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIsDeprecated(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDeprecationReason(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar getName() const = 0; + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableScalar getIsDeprecated() const = 0; + virtual service::AwaitableScalar> getDeprecationReason() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName() const final + { + return { _pimpl->getName() }; + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableScalar getIsDeprecated() const final + { + return { _pimpl->getIsDeprecated() }; + } + + service::AwaitableScalar> getDeprecationReason() const final + { + return { _pimpl->getDeprecationReason() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT EnumValue(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~EnumValue(); +}; + +} // namespace graphql::introspection::object + +#endif // ENUMVALUEOBJECT_H diff --git a/src/introspection/FieldObject.cpp b/src/introspection/FieldObject.cpp new file mode 100644 index 00000000..93553442 --- /dev/null +++ b/src/introspection/FieldObject.cpp @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "FieldObject.h" +#include "InputValueObject.h" +#include "TypeObject.h" + +#include "graphqlservice/internal/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::introspection { +namespace object { + +Field::Field(std::shared_ptr pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::make_unique>(std::move(pimpl)) } +{ +} + +Field::~Field() +{ + // This is empty, but explicitly defined here so that it can access the un-exported destructor + // of the implementation type. +} + +service::TypeNames Field::getTypeNames() const noexcept +{ + return { + R"gql(__Field)gql"sv + }; +} + +service::ResolverMap Field::getResolvers() const noexcept +{ + return { + { R"gql(args)gql"sv, [this](service::ResolverParams&& params) { return resolveArgs(std::move(params)); } }, + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(type)gql"sv, [this](service::ResolverParams&& params) { return resolveType(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(description)gql"sv, [this](service::ResolverParams&& params) { return resolveDescription(std::move(params)); } }, + { R"gql(isDeprecated)gql"sv, [this](service::ResolverParams&& params) { return resolveIsDeprecated(std::move(params)); } }, + { R"gql(deprecationReason)gql"sv, [this](service::ResolverParams&& params) { return resolveDeprecationReason(std::move(params)); } } + }; +} + +service::AwaitableResolver Field::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getName(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Field::resolveDescription(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getDescription(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Field::resolveArgs(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getArgs(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Field::resolveType(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getType(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Field::resolveIsDeprecated(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getIsDeprecated(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Field::resolveDeprecationReason(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getDeprecationReason(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Field::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(__Field)gql" }, std::move(params)); +} + +} // namespace object + +void AddFieldDetails(const std::shared_ptr& typeField, const std::shared_ptr& schema) +{ + typeField->AddFields({ + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(args)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__InputValue)gql"sv))))), + schema::Field::Make(R"gql(type)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__Type)gql"sv))), + schema::Field::Make(R"gql(isDeprecated)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv))), + schema::Field::Make(R"gql(deprecationReason)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::introspection diff --git a/src/introspection/FieldObject.h b/src/introspection/FieldObject.h new file mode 100644 index 00000000..778286e0 --- /dev/null +++ b/src/introspection/FieldObject.h @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef FIELDOBJECT_H +#define FIELDOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class Field + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveArgs(service::ResolverParams&& params) const; + service::AwaitableResolver resolveType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveIsDeprecated(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDeprecationReason(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar getName() const = 0; + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableObject>> getArgs() const = 0; + virtual service::AwaitableObject> getType() const = 0; + virtual service::AwaitableScalar getIsDeprecated() const = 0; + virtual service::AwaitableScalar> getDeprecationReason() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName() const final + { + return { _pimpl->getName() }; + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableObject>> getArgs() const final + { + return { _pimpl->getArgs() }; + } + + service::AwaitableObject> getType() const final + { + return { _pimpl->getType() }; + } + + service::AwaitableScalar getIsDeprecated() const final + { + return { _pimpl->getIsDeprecated() }; + } + + service::AwaitableScalar> getDeprecationReason() const final + { + return { _pimpl->getDeprecationReason() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT Field(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~Field(); +}; + +} // namespace graphql::introspection::object + +#endif // FIELDOBJECT_H diff --git a/src/introspection/InputValueObject.cpp b/src/introspection/InputValueObject.cpp new file mode 100644 index 00000000..bd58ef3a --- /dev/null +++ b/src/introspection/InputValueObject.cpp @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "InputValueObject.h" +#include "TypeObject.h" + +#include "graphqlservice/internal/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::introspection { +namespace object { + +InputValue::InputValue(std::shared_ptr pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::make_unique>(std::move(pimpl)) } +{ +} + +InputValue::~InputValue() +{ + // This is empty, but explicitly defined here so that it can access the un-exported destructor + // of the implementation type. +} + +service::TypeNames InputValue::getTypeNames() const noexcept +{ + return { + R"gql(__InputValue)gql"sv + }; +} + +service::ResolverMap InputValue::getResolvers() const noexcept +{ + return { + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(type)gql"sv, [this](service::ResolverParams&& params) { return resolveType(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(description)gql"sv, [this](service::ResolverParams&& params) { return resolveDescription(std::move(params)); } }, + { R"gql(defaultValue)gql"sv, [this](service::ResolverParams&& params) { return resolveDefaultValue(std::move(params)); } } + }; +} + +service::AwaitableResolver InputValue::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getName(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver InputValue::resolveDescription(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getDescription(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver InputValue::resolveType(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getType(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver InputValue::resolveDefaultValue(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getDefaultValue(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver InputValue::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(__InputValue)gql" }, std::move(params)); +} + +} // namespace object + +void AddInputValueDetails(const std::shared_ptr& typeInputValue, const std::shared_ptr& schema) +{ + typeInputValue->AddFields({ + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv))), + schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(type)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__Type)gql"sv))), + schema::Field::Make(R"gql(defaultValue)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::introspection diff --git a/src/introspection/InputValueObject.h b/src/introspection/InputValueObject.h new file mode 100644 index 00000000..1b9ed622 --- /dev/null +++ b/src/introspection/InputValueObject.h @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef INPUTVALUEOBJECT_H +#define INPUTVALUEOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class InputValue + : public service::Object +{ +private: + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDefaultValue(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar getName() const = 0; + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableObject> getType() const = 0; + virtual service::AwaitableScalar> getDefaultValue() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getName() const final + { + return { _pimpl->getName() }; + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableObject> getType() const final + { + return { _pimpl->getType() }; + } + + service::AwaitableScalar> getDefaultValue() const final + { + return { _pimpl->getDefaultValue() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT InputValue(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~InputValue(); +}; + +} // namespace graphql::introspection::object + +#endif // INPUTVALUEOBJECT_H diff --git a/src/introspection/IntrospectionSchema.cpp b/src/introspection/IntrospectionSchema.cpp new file mode 100644 index 00000000..6ea44bde --- /dev/null +++ b/src/introspection/IntrospectionSchema.cpp @@ -0,0 +1,246 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "graphqlservice/internal/Introspection.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql { +namespace service { + +static const std::array s_namesTypeKind = { + R"gql(SCALAR)gql"sv, + R"gql(OBJECT)gql"sv, + R"gql(INTERFACE)gql"sv, + R"gql(UNION)gql"sv, + R"gql(ENUM)gql"sv, + R"gql(INPUT_OBJECT)gql"sv, + R"gql(LIST)gql"sv, + R"gql(NON_NULL)gql"sv +}; + +template <> +introspection::TypeKind ModifiedArgument::convert(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid __TypeKind value)ex" } }; + } + + const auto itr = std::find(s_namesTypeKind.cbegin(), s_namesTypeKind.cend(), value.get()); + + if (itr == s_namesTypeKind.cend()) + { + throw service::schema_exception { { R"ex(not a valid __TypeKind value)ex" } }; + } + + return static_cast(itr - s_namesTypeKind.cbegin()); +} + +template <> +service::AwaitableResolver ModifiedResult::convert(service::AwaitableScalar result, ResolverParams params) +{ + return resolve(std::move(result), std::move(params), + [](introspection::TypeKind value, const ResolverParams&) + { + response::Value result(response::Type::EnumValue); + + result.set(std::string { s_namesTypeKind[static_cast(value)] }); + + return result; + }); +} + +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid __TypeKind value)ex" } }; + } + + const auto itr = std::find(s_namesTypeKind.cbegin(), s_namesTypeKind.cend(), value.get()); + + if (itr == s_namesTypeKind.cend()) + { + throw service::schema_exception { { R"ex(not a valid __TypeKind value)ex" } }; + } +} + +static const std::array s_namesDirectiveLocation = { + R"gql(QUERY)gql"sv, + R"gql(MUTATION)gql"sv, + R"gql(SUBSCRIPTION)gql"sv, + R"gql(FIELD)gql"sv, + R"gql(FRAGMENT_DEFINITION)gql"sv, + R"gql(FRAGMENT_SPREAD)gql"sv, + R"gql(INLINE_FRAGMENT)gql"sv, + R"gql(VARIABLE_DEFINITION)gql"sv, + R"gql(SCHEMA)gql"sv, + R"gql(SCALAR)gql"sv, + R"gql(OBJECT)gql"sv, + R"gql(FIELD_DEFINITION)gql"sv, + R"gql(ARGUMENT_DEFINITION)gql"sv, + R"gql(INTERFACE)gql"sv, + R"gql(UNION)gql"sv, + R"gql(ENUM)gql"sv, + R"gql(ENUM_VALUE)gql"sv, + R"gql(INPUT_OBJECT)gql"sv, + R"gql(INPUT_FIELD_DEFINITION)gql"sv +}; + +template <> +introspection::DirectiveLocation ModifiedArgument::convert(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid __DirectiveLocation value)ex" } }; + } + + const auto itr = std::find(s_namesDirectiveLocation.cbegin(), s_namesDirectiveLocation.cend(), value.get()); + + if (itr == s_namesDirectiveLocation.cend()) + { + throw service::schema_exception { { R"ex(not a valid __DirectiveLocation value)ex" } }; + } + + return static_cast(itr - s_namesDirectiveLocation.cbegin()); +} + +template <> +service::AwaitableResolver ModifiedResult::convert(service::AwaitableScalar result, ResolverParams params) +{ + return resolve(std::move(result), std::move(params), + [](introspection::DirectiveLocation value, const ResolverParams&) + { + response::Value result(response::Type::EnumValue); + + result.set(std::string { s_namesDirectiveLocation[static_cast(value)] }); + + return result; + }); +} + +template <> +void ModifiedResult::validateScalar(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { R"ex(not a valid __DirectiveLocation value)ex" } }; + } + + const auto itr = std::find(s_namesDirectiveLocation.cbegin(), s_namesDirectiveLocation.cend(), value.get()); + + if (itr == s_namesDirectiveLocation.cend()) + { + throw service::schema_exception { { R"ex(not a valid __DirectiveLocation value)ex" } }; + } +} + +} // namespace service + +namespace introspection { + +void AddTypesToSchema(const std::shared_ptr& schema) +{ + schema->AddType(R"gql(Boolean)gql"sv, schema::ScalarType::Make(R"gql(Boolean)gql"sv, R"md(Built-in type)md"sv, R"url(https://spec.graphql.org/October2021/#sec-Boolean)url"sv)); + schema->AddType(R"gql(Float)gql"sv, schema::ScalarType::Make(R"gql(Float)gql"sv, R"md(Built-in type)md"sv, R"url(https://spec.graphql.org/October2021/#sec-Float)url"sv)); + schema->AddType(R"gql(ID)gql"sv, schema::ScalarType::Make(R"gql(ID)gql"sv, R"md(Built-in type)md"sv, R"url(https://spec.graphql.org/October2021/#sec-ID)url"sv)); + schema->AddType(R"gql(Int)gql"sv, schema::ScalarType::Make(R"gql(Int)gql"sv, R"md(Built-in type)md"sv, R"url(https://spec.graphql.org/October2021/#sec-Int)url"sv)); + schema->AddType(R"gql(String)gql"sv, schema::ScalarType::Make(R"gql(String)gql"sv, R"md(Built-in type)md"sv, R"url(https://spec.graphql.org/October2021/#sec-String)url"sv)); + auto typeTypeKind = schema::EnumType::Make(R"gql(__TypeKind)gql"sv, R"md()md"sv); + schema->AddType(R"gql(__TypeKind)gql"sv, typeTypeKind); + auto typeDirectiveLocation = schema::EnumType::Make(R"gql(__DirectiveLocation)gql"sv, R"md()md"sv); + schema->AddType(R"gql(__DirectiveLocation)gql"sv, typeDirectiveLocation); + auto typeSchema = schema::ObjectType::Make(R"gql(__Schema)gql"sv, R"md()md"sv); + schema->AddType(R"gql(__Schema)gql"sv, typeSchema); + auto typeType = schema::ObjectType::Make(R"gql(__Type)gql"sv, R"md()md"sv); + schema->AddType(R"gql(__Type)gql"sv, typeType); + auto typeField = schema::ObjectType::Make(R"gql(__Field)gql"sv, R"md()md"sv); + schema->AddType(R"gql(__Field)gql"sv, typeField); + auto typeInputValue = schema::ObjectType::Make(R"gql(__InputValue)gql"sv, R"md()md"sv); + schema->AddType(R"gql(__InputValue)gql"sv, typeInputValue); + auto typeEnumValue = schema::ObjectType::Make(R"gql(__EnumValue)gql"sv, R"md()md"sv); + schema->AddType(R"gql(__EnumValue)gql"sv, typeEnumValue); + auto typeDirective = schema::ObjectType::Make(R"gql(__Directive)gql"sv, R"md()md"sv); + schema->AddType(R"gql(__Directive)gql"sv, typeDirective); + + typeTypeKind->AddEnumValues({ + { service::s_namesTypeKind[static_cast(introspection::TypeKind::SCALAR)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::OBJECT)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::INTERFACE)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::UNION)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::ENUM)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::INPUT_OBJECT)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::LIST)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::NON_NULL)], R"md()md"sv, std::nullopt } + }); + typeDirectiveLocation->AddEnumValues({ + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::QUERY)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::MUTATION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SUBSCRIPTION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FIELD)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FRAGMENT_DEFINITION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FRAGMENT_SPREAD)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INLINE_FRAGMENT)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::VARIABLE_DEFINITION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SCHEMA)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SCALAR)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::OBJECT)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FIELD_DEFINITION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ARGUMENT_DEFINITION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INTERFACE)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::UNION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ENUM)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ENUM_VALUE)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INPUT_OBJECT)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INPUT_FIELD_DEFINITION)], R"md()md"sv, std::nullopt } + }); + + AddSchemaDetails(typeSchema, schema); + AddTypeDetails(typeType, schema); + AddFieldDetails(typeField, schema); + AddInputValueDetails(typeInputValue, schema); + AddEnumValueDetails(typeEnumValue, schema); + AddDirectiveDetails(typeDirective, schema); + + schema->AddDirective(schema::Directive::Make(R"gql(skip)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD, + introspection::DirectiveLocation::FRAGMENT_SPREAD, + introspection::DirectiveLocation::INLINE_FRAGMENT + }, { + schema::InputValue::Make(R"gql(if)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv)), R"gql()gql"sv) + }, false)); + schema->AddDirective(schema::Directive::Make(R"gql(include)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD, + introspection::DirectiveLocation::FRAGMENT_SPREAD, + introspection::DirectiveLocation::INLINE_FRAGMENT + }, { + schema::InputValue::Make(R"gql(if)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv)), R"gql()gql"sv) + }, false)); + schema->AddDirective(schema::Directive::Make(R"gql(deprecated)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD_DEFINITION, + introspection::DirectiveLocation::ENUM_VALUE + }, { + schema::InputValue::Make(R"gql(reason)gql"sv, R"md()md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql("No longer supported")gql"sv) + }, false)); + schema->AddDirective(schema::Directive::Make(R"gql(specifiedBy)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::SCALAR + }, { + schema::InputValue::Make(R"gql(url)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv) + }, false)); +} + +} // namespace introspection +} // namespace graphql diff --git a/src/introspection/IntrospectionSchema.h b/src/introspection/IntrospectionSchema.h new file mode 100644 index 00000000..9507b218 --- /dev/null +++ b/src/introspection/IntrospectionSchema.h @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef INTROSPECTIONSCHEMA_H +#define INTROSPECTIONSCHEMA_H + +#include "graphqlservice/internal/Schema.h" + +// Check if the library version is compatible with schemagen 4.0.0 +static_assert(graphql::internal::MajorVersion == 4, "regenerate with schemagen: major version mismatch"); +static_assert(graphql::internal::MinorVersion == 0, "regenerate with schemagen: minor version mismatch"); + +// clang-format off +#ifdef GRAPHQL_DLLEXPORTS + #ifdef IMPL_GRAPHQLINTROSPECTION_DLL + #define GRAPHQLINTROSPECTION_EXPORT __declspec(dllexport) + #else // !IMPL_GRAPHQLINTROSPECTION_DLL + #define GRAPHQLINTROSPECTION_EXPORT __declspec(dllimport) + #endif // !IMPL_GRAPHQLINTROSPECTION_DLL +#else // !GRAPHQL_DLLEXPORTS + #define GRAPHQLINTROSPECTION_EXPORT +#endif // !GRAPHQL_DLLEXPORTS +// clang-format on + +#include +#include +#include + +namespace graphql { +namespace introspection { + +enum class TypeKind +{ + SCALAR, + OBJECT, + INTERFACE, + UNION, + ENUM, + INPUT_OBJECT, + LIST, + NON_NULL +}; + +enum class DirectiveLocation +{ + QUERY, + MUTATION, + SUBSCRIPTION, + FIELD, + FRAGMENT_DEFINITION, + FRAGMENT_SPREAD, + INLINE_FRAGMENT, + VARIABLE_DEFINITION, + SCHEMA, + SCALAR, + OBJECT, + FIELD_DEFINITION, + ARGUMENT_DEFINITION, + INTERFACE, + UNION, + ENUM, + ENUM_VALUE, + INPUT_OBJECT, + INPUT_FIELD_DEFINITION +}; + +class Schema; +class Type; +class Field; +class InputValue; +class EnumValue; +class Directive; + +namespace object { + +class Schema; +class Type; +class Field; +class InputValue; +class EnumValue; +class Directive; + +} // namespace object + +void AddSchemaDetails(const std::shared_ptr& typeSchema, const std::shared_ptr& schema); +void AddTypeDetails(const std::shared_ptr& typeType, const std::shared_ptr& schema); +void AddFieldDetails(const std::shared_ptr& typeField, const std::shared_ptr& schema); +void AddInputValueDetails(const std::shared_ptr& typeInputValue, const std::shared_ptr& schema); +void AddEnumValueDetails(const std::shared_ptr& typeEnumValue, const std::shared_ptr& schema); +void AddDirectiveDetails(const std::shared_ptr& typeDirective, const std::shared_ptr& schema); + +GRAPHQLINTROSPECTION_EXPORT void AddTypesToSchema(const std::shared_ptr& schema); + +} // namespace introspection + +namespace service { + +#ifdef GRAPHQL_DLLEXPORTS +// Export all of the built-in converters +template <> +GRAPHQLINTROSPECTION_EXPORT introspection::TypeKind ModifiedArgument::convert( + const response::Value& value); +template <> +GRAPHQLINTROSPECTION_EXPORT AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params); +template <> +GRAPHQLINTROSPECTION_EXPORT void ModifiedResult::validateScalar( + const response::Value& value); +template <> +GRAPHQLINTROSPECTION_EXPORT introspection::DirectiveLocation ModifiedArgument::convert( + const response::Value& value); +template <> +GRAPHQLINTROSPECTION_EXPORT AwaitableResolver ModifiedResult::convert( + AwaitableScalar result, ResolverParams params); +template <> +GRAPHQLINTROSPECTION_EXPORT void ModifiedResult::validateScalar( + const response::Value& value); +#endif // GRAPHQL_DLLEXPORTS + +} // namespace service +} // namespace graphql + +#endif // INTROSPECTIONSCHEMA_H diff --git a/src/introspection/SchemaObject.cpp b/src/introspection/SchemaObject.cpp new file mode 100644 index 00000000..d0face1e --- /dev/null +++ b/src/introspection/SchemaObject.cpp @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "SchemaObject.h" +#include "TypeObject.h" +#include "DirectiveObject.h" + +#include "graphqlservice/internal/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::introspection { +namespace object { + +Schema::Schema(std::shared_ptr pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::make_unique>(std::move(pimpl)) } +{ +} + +Schema::~Schema() +{ + // This is empty, but explicitly defined here so that it can access the un-exported destructor + // of the implementation type. +} + +service::TypeNames Schema::getTypeNames() const noexcept +{ + return { + R"gql(__Schema)gql"sv + }; +} + +service::ResolverMap Schema::getResolvers() const noexcept +{ + return { + { R"gql(types)gql"sv, [this](service::ResolverParams&& params) { return resolveTypes(std::move(params)); } }, + { R"gql(queryType)gql"sv, [this](service::ResolverParams&& params) { return resolveQueryType(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(directives)gql"sv, [this](service::ResolverParams&& params) { return resolveDirectives(std::move(params)); } }, + { R"gql(description)gql"sv, [this](service::ResolverParams&& params) { return resolveDescription(std::move(params)); } }, + { R"gql(mutationType)gql"sv, [this](service::ResolverParams&& params) { return resolveMutationType(std::move(params)); } }, + { R"gql(subscriptionType)gql"sv, [this](service::ResolverParams&& params) { return resolveSubscriptionType(std::move(params)); } } + }; +} + +service::AwaitableResolver Schema::resolveDescription(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getDescription(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Schema::resolveTypes(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getTypes(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Schema::resolveQueryType(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getQueryType(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Schema::resolveMutationType(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getMutationType(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Schema::resolveSubscriptionType(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getSubscriptionType(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Schema::resolveDirectives(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getDirectives(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Schema::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(__Schema)gql" }, std::move(params)); +} + +} // namespace object + +void AddSchemaDetails(const std::shared_ptr& typeSchema, const std::shared_ptr& schema) +{ + typeSchema->AddFields({ + schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(types)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__Type)gql"sv))))), + schema::Field::Make(R"gql(queryType)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__Type)gql"sv))), + schema::Field::Make(R"gql(mutationType)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(__Type)gql"sv)), + schema::Field::Make(R"gql(subscriptionType)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(__Type)gql"sv)), + schema::Field::Make(R"gql(directives)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__Directive)gql"sv))))) + }); +} + +} // namespace graphql::introspection diff --git a/src/introspection/SchemaObject.h b/src/introspection/SchemaObject.h new file mode 100644 index 00000000..a8f05373 --- /dev/null +++ b/src/introspection/SchemaObject.h @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef SCHEMAOBJECT_H +#define SCHEMAOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class Schema + : public service::Object +{ +private: + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveTypes(service::ResolverParams&& params) const; + service::AwaitableResolver resolveQueryType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveMutationType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveSubscriptionType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDirectives(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableObject>> getTypes() const = 0; + virtual service::AwaitableObject> getQueryType() const = 0; + virtual service::AwaitableObject> getMutationType() const = 0; + virtual service::AwaitableObject> getSubscriptionType() const = 0; + virtual service::AwaitableObject>> getDirectives() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableObject>> getTypes() const final + { + return { _pimpl->getTypes() }; + } + + service::AwaitableObject> getQueryType() const final + { + return { _pimpl->getQueryType() }; + } + + service::AwaitableObject> getMutationType() const final + { + return { _pimpl->getMutationType() }; + } + + service::AwaitableObject> getSubscriptionType() const final + { + return { _pimpl->getSubscriptionType() }; + } + + service::AwaitableObject>> getDirectives() const final + { + return { _pimpl->getDirectives() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT Schema(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~Schema(); +}; + +} // namespace graphql::introspection::object + +#endif // SCHEMAOBJECT_H diff --git a/src/introspection/TypeObject.cpp b/src/introspection/TypeObject.cpp new file mode 100644 index 00000000..08c3e625 --- /dev/null +++ b/src/introspection/TypeObject.cpp @@ -0,0 +1,208 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#include "TypeObject.h" +#include "FieldObject.h" +#include "TypeObject.h" +#include "EnumValueObject.h" +#include "InputValueObject.h" + +#include "graphqlservice/internal/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::introspection { +namespace object { + +Type::Type(std::shared_ptr pimpl) noexcept + : service::Object{ getTypeNames(), getResolvers() } + , _pimpl { std::make_unique>(std::move(pimpl)) } +{ +} + +Type::~Type() +{ + // This is empty, but explicitly defined here so that it can access the un-exported destructor + // of the implementation type. +} + +service::TypeNames Type::getTypeNames() const noexcept +{ + return { + R"gql(__Type)gql"sv + }; +} + +service::ResolverMap Type::getResolvers() const noexcept +{ + return { + { R"gql(kind)gql"sv, [this](service::ResolverParams&& params) { return resolveKind(std::move(params)); } }, + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(fields)gql"sv, [this](service::ResolverParams&& params) { return resolveFields(std::move(params)); } }, + { R"gql(ofType)gql"sv, [this](service::ResolverParams&& params) { return resolveOfType(std::move(params)); } }, + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(enumValues)gql"sv, [this](service::ResolverParams&& params) { return resolveEnumValues(std::move(params)); } }, + { R"gql(interfaces)gql"sv, [this](service::ResolverParams&& params) { return resolveInterfaces(std::move(params)); } }, + { R"gql(description)gql"sv, [this](service::ResolverParams&& params) { return resolveDescription(std::move(params)); } }, + { R"gql(inputFields)gql"sv, [this](service::ResolverParams&& params) { return resolveInputFields(std::move(params)); } }, + { R"gql(possibleTypes)gql"sv, [this](service::ResolverParams&& params) { return resolvePossibleTypes(std::move(params)); } }, + { R"gql(specifiedByURL)gql"sv, [this](service::ResolverParams&& params) { return resolveSpecifiedByURL(std::move(params)); } } + }; +} + +service::AwaitableResolver Type::resolveKind(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getKind(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Type::resolveName(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getName(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Type::resolveDescription(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getDescription(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Type::resolveFields(service::ResolverParams&& params) const +{ + static const auto defaultArguments = []() + { + response::Value values(response::Type::Map); + response::Value entry; + + entry = response::Value(false); + values.emplace_back("includeDeprecated", std::move(entry)); + + return values; + }(); + + auto pairIncludeDeprecated = service::ModifiedArgument::find("includeDeprecated", params.arguments); + auto argIncludeDeprecated = (pairIncludeDeprecated.second + ? std::move(pairIncludeDeprecated.first) + : service::ModifiedArgument::require("includeDeprecated", defaultArguments)); + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getFields(std::move(argIncludeDeprecated)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Type::resolveInterfaces(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getInterfaces(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Type::resolvePossibleTypes(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getPossibleTypes(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Type::resolveEnumValues(service::ResolverParams&& params) const +{ + static const auto defaultArguments = []() + { + response::Value values(response::Type::Map); + response::Value entry; + + entry = response::Value(false); + values.emplace_back("includeDeprecated", std::move(entry)); + + return values; + }(); + + auto pairIncludeDeprecated = service::ModifiedArgument::find("includeDeprecated", params.arguments); + auto argIncludeDeprecated = (pairIncludeDeprecated.second + ? std::move(pairIncludeDeprecated.first) + : service::ModifiedArgument::require("includeDeprecated", defaultArguments)); + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getEnumValues(std::move(argIncludeDeprecated)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Type::resolveInputFields(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getInputFields(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Type::resolveOfType(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getOfType(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Type::resolveSpecifiedByURL(service::ResolverParams&& params) const +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = _pimpl->getSpecifiedByURL(); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::AwaitableResolver Type::resolve_typename(service::ResolverParams&& params) const +{ + return service::ModifiedResult::convert(std::string{ R"gql(__Type)gql" }, std::move(params)); +} + +} // namespace object + +void AddTypeDetails(const std::shared_ptr& typeType, const std::shared_ptr& schema) +{ + typeType->AddFields({ + schema::Field::Make(R"gql(kind)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__TypeKind)gql"sv))), + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)), + schema::Field::Make(R"gql(fields)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__Field)gql"sv))), { + schema::InputValue::Make(R"gql(includeDeprecated)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Boolean)gql"sv), R"gql(false)gql"sv) + }), + schema::Field::Make(R"gql(interfaces)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__Type)gql"sv)))), + schema::Field::Make(R"gql(possibleTypes)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__Type)gql"sv)))), + schema::Field::Make(R"gql(enumValues)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__EnumValue)gql"sv))), { + schema::InputValue::Make(R"gql(includeDeprecated)gql"sv, R"md()md"sv, schema->LookupType(R"gql(Boolean)gql"sv), R"gql(false)gql"sv) + }), + schema::Field::Make(R"gql(inputFields)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(__InputValue)gql"sv)))), + schema::Field::Make(R"gql(ofType)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(__Type)gql"sv)), + schema::Field::Make(R"gql(specifiedByURL)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType(R"gql(String)gql"sv)) + }); +} + +} // namespace graphql::introspection diff --git a/src/introspection/TypeObject.h b/src/introspection/TypeObject.h new file mode 100644 index 00000000..32bc9bdb --- /dev/null +++ b/src/introspection/TypeObject.h @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// WARNING! Do not edit this file manually, your changes will be overwritten. + +#pragma once + +#ifndef TYPEOBJECT_H +#define TYPEOBJECT_H + +#include "IntrospectionSchema.h" + +namespace graphql::introspection::object { + +class Type + : public service::Object +{ +private: + service::AwaitableResolver resolveKind(service::ResolverParams&& params) const; + service::AwaitableResolver resolveName(service::ResolverParams&& params) const; + service::AwaitableResolver resolveDescription(service::ResolverParams&& params) const; + service::AwaitableResolver resolveFields(service::ResolverParams&& params) const; + service::AwaitableResolver resolveInterfaces(service::ResolverParams&& params) const; + service::AwaitableResolver resolvePossibleTypes(service::ResolverParams&& params) const; + service::AwaitableResolver resolveEnumValues(service::ResolverParams&& params) const; + service::AwaitableResolver resolveInputFields(service::ResolverParams&& params) const; + service::AwaitableResolver resolveOfType(service::ResolverParams&& params) const; + service::AwaitableResolver resolveSpecifiedByURL(service::ResolverParams&& params) const; + + service::AwaitableResolver resolve_typename(service::ResolverParams&& params) const; + + struct Concept + { + virtual ~Concept() = default; + + virtual service::AwaitableScalar getKind() const = 0; + virtual service::AwaitableScalar> getName() const = 0; + virtual service::AwaitableScalar> getDescription() const = 0; + virtual service::AwaitableObject>>> getFields(std::optional&& includeDeprecatedArg) const = 0; + virtual service::AwaitableObject>>> getInterfaces() const = 0; + virtual service::AwaitableObject>>> getPossibleTypes() const = 0; + virtual service::AwaitableObject>>> getEnumValues(std::optional&& includeDeprecatedArg) const = 0; + virtual service::AwaitableObject>>> getInputFields() const = 0; + virtual service::AwaitableObject> getOfType() const = 0; + virtual service::AwaitableScalar> getSpecifiedByURL() const = 0; + }; + + template + struct Model + : Concept + { + Model(std::shared_ptr&& pimpl) noexcept + : _pimpl { std::move(pimpl) } + { + } + + service::AwaitableScalar getKind() const final + { + return { _pimpl->getKind() }; + } + + service::AwaitableScalar> getName() const final + { + return { _pimpl->getName() }; + } + + service::AwaitableScalar> getDescription() const final + { + return { _pimpl->getDescription() }; + } + + service::AwaitableObject>>> getFields(std::optional&& includeDeprecatedArg) const final + { + return { _pimpl->getFields(std::move(includeDeprecatedArg)) }; + } + + service::AwaitableObject>>> getInterfaces() const final + { + return { _pimpl->getInterfaces() }; + } + + service::AwaitableObject>>> getPossibleTypes() const final + { + return { _pimpl->getPossibleTypes() }; + } + + service::AwaitableObject>>> getEnumValues(std::optional&& includeDeprecatedArg) const final + { + return { _pimpl->getEnumValues(std::move(includeDeprecatedArg)) }; + } + + service::AwaitableObject>>> getInputFields() const final + { + return { _pimpl->getInputFields() }; + } + + service::AwaitableObject> getOfType() const final + { + return { _pimpl->getOfType() }; + } + + service::AwaitableScalar> getSpecifiedByURL() const final + { + return { _pimpl->getSpecifiedByURL() }; + } + + private: + const std::shared_ptr _pimpl; + }; + + const std::unique_ptr _pimpl; + + service::TypeNames getTypeNames() const noexcept; + service::ResolverMap getResolvers() const noexcept; + +public: + GRAPHQLINTROSPECTION_EXPORT Type(std::shared_ptr pimpl) noexcept; + GRAPHQLINTROSPECTION_EXPORT ~Type(); +}; + +} // namespace graphql::introspection::object + +#endif // TYPEOBJECT_H diff --git a/src/introspection/introspection_schema_files b/src/introspection/introspection_schema_files new file mode 100644 index 00000000..fba57600 --- /dev/null +++ b/src/introspection/introspection_schema_files @@ -0,0 +1,7 @@ +IntrospectionSchema.cpp +SchemaObject.cpp +TypeObject.cpp +FieldObject.cpp +InputValueObject.cpp +EnumValueObject.cpp +DirectiveObject.cpp diff --git a/src/introspection/schema.introspection.graphql b/src/introspection/schema.introspection.graphql new file mode 100644 index 00000000..5145f3b2 --- /dev/null +++ b/src/introspection/schema.introspection.graphql @@ -0,0 +1,104 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +# Introspection Schema: https://spec.graphql.org/October2021/#sec-Schema-Introspection.Schema-Introspection-Schema +type __Schema { + description: String + types: [__Type!]! + queryType: __Type! + mutationType: __Type + subscriptionType: __Type + directives: [__Directive!]! +} + +type __Type { + kind: __TypeKind! + name: String + description: String + # must be non-null for OBJECT and INTERFACE, otherwise null. + fields(includeDeprecated: Boolean = false): [__Field!] + # must be non-null for OBJECT and INTERFACE, otherwise null. + interfaces: [__Type!] + # must be non-null for INTERFACE and UNION, otherwise null. + possibleTypes: [__Type!] + # must be non-null for ENUM, otherwise null. + enumValues(includeDeprecated: Boolean = false): [__EnumValue!] + # must be non-null for INPUT_OBJECT, otherwise null. + inputFields: [__InputValue!] + # must be non-null for NON_NULL and LIST, otherwise null. + ofType: __Type + # may be non-null for custom SCALAR, otherwise null. + specifiedByURL: String +} + +enum __TypeKind { + SCALAR + OBJECT + INTERFACE + UNION + ENUM + INPUT_OBJECT + LIST + NON_NULL +} + +type __Field { + name: String! + description: String + args: [__InputValue!]! + type: __Type! + isDeprecated: Boolean! + deprecationReason: String +} + +type __InputValue { + name: String! + description: String + type: __Type! + defaultValue: String +} + +type __EnumValue { + name: String! + description: String + isDeprecated: Boolean! + deprecationReason: String +} + +type __Directive { + name: String! + description: String + locations: [__DirectiveLocation!]! + args: [__InputValue!]! + isRepeatable: Boolean! +} + +enum __DirectiveLocation { + QUERY + MUTATION + SUBSCRIPTION + FIELD + FRAGMENT_DEFINITION + FRAGMENT_SPREAD + INLINE_FRAGMENT + VARIABLE_DEFINITION + SCHEMA + SCALAR + OBJECT + FIELD_DEFINITION + ARGUMENT_DEFINITION + INTERFACE + UNION + ENUM + ENUM_VALUE + INPUT_OBJECT + INPUT_FIELD_DEFINITION +} + +# These directives are always defined and should be included in the Introspection schema. +directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT +directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT +directive @deprecated( + reason: String = "No longer supported" +) on FIELD_DEFINITION | ENUM_VALUE +directive @specifiedBy(url: String!) on SCALAR diff --git a/test/ArgumentTests.cpp b/test/ArgumentTests.cpp index 9f73f5c1..5227d868 100644 --- a/test/ArgumentTests.cpp +++ b/test/ArgumentTests.cpp @@ -147,7 +147,7 @@ TEST(ArgumentsCase, TaskStateEnum) { response::Value response(response::Type::Map); response::Value status(response::Type::EnumValue); - status.set("Started"); + status.set("Started"); response.emplace_back("status", std::move(status)); today::TaskState actual = static_cast(-1); @@ -229,7 +229,7 @@ TEST(ArgumentsCase, ScalarArgumentMap) values = actual.release(); ASSERT_EQ(1, values.size()) << "should have a single key/value"; ASSERT_EQ("foo", values.front().first) << "should match the key"; - ASSERT_EQ("bar", values.front().second.get()) << "should match the value"; + ASSERT_EQ("bar", values.front().second.get()) << "should match the value"; } TEST(ArgumentsCase, ScalarArgumentList) @@ -251,8 +251,8 @@ TEST(ArgumentsCase, ScalarArgumentList) ASSERT_EQ(response::Type::List, actual.type()) << "should parse the array"; values = actual.release(); ASSERT_EQ(2, values.size()) << "should have 2 values"; - ASSERT_EQ("foo", values.front().get()) << "should match the value"; - ASSERT_EQ("bar", values.back().get()) << "should match the value"; + ASSERT_EQ("foo", values.front().get()) << "should match the value"; + ASSERT_EQ("bar", values.back().get()) << "should match the value"; } TEST(ArgumentsCase, ScalarArgumentNull) @@ -289,7 +289,7 @@ TEST(ArgumentsCase, ScalarArgumentString) } ASSERT_EQ(response::Type::String, actual.type()) << "should parse the object"; - ASSERT_EQ("foobar", actual.get()) << "should match the value"; + ASSERT_EQ("foobar", actual.get()) << "should match the value"; } TEST(ArgumentsCase, FindArgumentNoTemplateArguments) @@ -309,7 +309,7 @@ TEST(ArgumentsCase, FindArgumentNoTemplateArguments) ASSERT_TRUE(actual.second) << "should find the argument"; ASSERT_EQ(response::Type::String, actual.first.type()) << "should parse the object"; - ASSERT_EQ("foobar", actual.first.get()) << "should match the value"; + ASSERT_EQ("foobar", actual.first.get()) << "should match the value"; } TEST(ArgumentsCase, FindArgumentEmptyTemplateArgs) @@ -329,5 +329,5 @@ TEST(ArgumentsCase, FindArgumentEmptyTemplateArgs) ASSERT_TRUE(actual.second) << "should find the argument"; ASSERT_EQ(response::Type::String, actual.first.type()) << "should parse the object"; - ASSERT_EQ("foobar", actual.first.get()) << "should match the value"; + ASSERT_EQ("foobar", actual.first.get()) << "should match the value"; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cba206bf..4ab213b6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -cmake_minimum_required(VERSION 3.8.2) +cmake_minimum_required(VERSION 3.15) find_package(GTest MODULE REQUIRED) @@ -16,7 +16,7 @@ gtest_add_tests(TARGET validation_tests) add_executable(today_tests TodayTests.cpp) target_link_libraries(today_tests PRIVATE - unifiedgraphql + todaygraphql graphqljson GTest::GTest GTest::Main) @@ -25,8 +25,10 @@ gtest_add_tests(TARGET today_tests) add_executable(client_tests ClientTests.cpp) target_link_libraries(client_tests PRIVATE - unifiedgraphql - todayclient + todaygraphql + query_client + mutate_client + subscribe_client GTest::GTest GTest::Main) add_bigobj_flag(client_tests) @@ -34,7 +36,7 @@ gtest_add_tests(TARGET client_tests) add_executable(nointrospection_tests NoIntrospectionTests.cpp) target_link_libraries(nointrospection_tests PRIVATE - unifiedgraphql_nointrospection + todaygraphql_nointrospection graphqljson GTest::GTest GTest::Main) @@ -43,7 +45,7 @@ gtest_add_tests(TARGET nointrospection_tests) add_executable(argument_tests ArgumentTests.cpp) target_link_libraries(argument_tests PRIVATE - unifiedgraphql + todaygraphql graphqljson GTest::GTest GTest::Main) @@ -55,9 +57,8 @@ target_link_libraries(pegtl_combined_tests PRIVATE taocpp::pegtl GTest::GTest GTest::Main) -target_include_directories(pegtl_combined_tests PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) +target_include_directories(pegtl_combined_tests PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/../include) gtest_add_tests(TARGET pegtl_combined_tests) add_executable(pegtl_executable_tests PegtlExecutableTests.cpp) @@ -65,9 +66,8 @@ target_link_libraries(pegtl_executable_tests PRIVATE taocpp::pegtl GTest::GTest GTest::Main) -target_include_directories(pegtl_executable_tests PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) +target_include_directories(pegtl_executable_tests PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/../include) gtest_add_tests(TARGET pegtl_executable_tests) add_executable(pegtl_schema_tests PegtlSchemaTests.cpp) @@ -75,9 +75,8 @@ target_link_libraries(pegtl_schema_tests PRIVATE taocpp::pegtl GTest::GTest GTest::Main) -target_include_directories(pegtl_schema_tests PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/../include - ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) +target_include_directories(pegtl_schema_tests PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/../include) gtest_add_tests(TARGET pegtl_schema_tests) add_executable(response_tests ResponseTests.cpp) @@ -106,8 +105,7 @@ if(WIN32 AND BUILD_SHARED_LIBS) graphqljson graphqlpeg graphqlresponse - graphqlclient - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../src) + graphqlclient) add_custom_target(copy_test_dlls DEPENDS copied_test_dlls) diff --git a/test/ClientTests.cpp b/test/ClientTests.cpp index eacbae0f..37068041 100644 --- a/test/ClientTests.cpp +++ b/test/ClientTests.cpp @@ -108,7 +108,7 @@ TEST_F(ClientCase, QueryEverything) response::Value variables(response::Type::Map); auto state = std::make_shared(1); auto result = - _service->resolve(std::launch::async, state, query, "", std::move(variables)).get(); + _service->resolve({ query, {}, std::move(variables), std::launch::async, state }).get(); EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; EXPECT_EQ(size_t(1), _getTasksCount) @@ -141,8 +141,7 @@ TEST_F(ClientCase, QueryEverything) ASSERT_TRUE(appointmentNode->subject.has_value()) << "subject should be set"; EXPECT_EQ("Lunch?", *(appointmentNode->subject)) << "subject should match"; ASSERT_TRUE(appointmentNode->when.has_value()) << "when should be set"; - EXPECT_EQ("tomorrow", appointmentNode->when->get()) - << "when should match"; + EXPECT_EQ("tomorrow", appointmentNode->when->get()) << "when should match"; EXPECT_FALSE(appointmentNode->isNow) << "isNow should match"; EXPECT_EQ("Appointment", appointmentNode->_typename) << "__typename should match"; @@ -181,7 +180,7 @@ TEST_F(ClientCase, QueryEverything) ASSERT_TRUE(anyType.subject.has_value()) << "subject should be set"; EXPECT_EQ("Lunch?", *(anyType.subject)) << "subject should match"; ASSERT_TRUE(anyType.when.has_value()) << "when should be set"; - EXPECT_EQ("tomorrow", anyType.when->get()) << "when should match"; + EXPECT_EQ("tomorrow", anyType.when->get()) << "when should match"; EXPECT_FALSE(anyType.isNow) << "isNow should match"; } catch (const std::logic_error& ex) @@ -201,7 +200,7 @@ TEST_F(ClientCase, MutateCompleteTask) std::make_optional("Hi There!"s) } }); auto state = std::make_shared(5); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); try { @@ -238,15 +237,18 @@ TEST_F(ClientCase, SubscribeNextAppointmentChangeDefault) response::Value variables(response::Type::Map); auto state = std::make_shared(6); response::Value result; - auto key = _service->subscribe(service::SubscriptionParams { state, - std::move(query), - "TestSubscription", - std::move(std::move(variables)) }, - [&result](std::future response) { - result = response.get(); - }); - _service->deliver("nextAppointmentChange", nullptr); - _service->unsubscribe(key); + auto key = _service + ->subscribe({ [&result](response::Value&& response) { + result = std::move(response); + }, + std::move(query), + "TestSubscription"s, + std::move(variables), + {}, + state }) + .get(); + _service->deliver({ "nextAppointmentChange"sv }).get(); + _service->unsubscribe({ key }).get(); try { @@ -263,8 +265,7 @@ TEST_F(ClientCase, SubscribeNextAppointmentChangeDefault) ASSERT_TRUE(appointmentNode->subject.has_value()) << "subject should be set"; EXPECT_EQ("Lunch?", *(appointmentNode->subject)) << "subject should match"; ASSERT_TRUE(appointmentNode->when.has_value()) << "when should be set"; - EXPECT_EQ("tomorrow", appointmentNode->when->get()) - << "when should match"; + EXPECT_EQ("tomorrow", appointmentNode->when->get()) << "when should match"; EXPECT_TRUE(appointmentNode->isNow) << "isNow should match"; } catch (const std::logic_error& ex) diff --git a/test/NoIntrospectionTests.cpp b/test/NoIntrospectionTests.cpp index cc052530..1115e938 100644 --- a/test/NoIntrospectionTests.cpp +++ b/test/NoIntrospectionTests.cpp @@ -13,7 +13,6 @@ using namespace graphql; using namespace std::literals; - // this is similar to TodayTests, will trust QueryEverything works // and then check if introspection is disabled @@ -35,32 +34,41 @@ class NoIntrospectionServiceCase : public ::testing::Test std::copy(fakeFolderId.cbegin(), fakeFolderId.cend(), _fakeFolderId.begin()); auto query = std::make_shared( - []() -> std::vector> - { - ++_getAppointmentsCount; - return { std::make_shared(response::IdType(_fakeAppointmentId), "tomorrow", "Lunch?", false) }; - }, []() -> std::vector> - { - ++_getTasksCount; - return { std::make_shared(response::IdType(_fakeTaskId), "Don't forget", true) }; - }, []() -> std::vector> - { - ++_getUnreadCountsCount; - return { std::make_shared(response::IdType(_fakeFolderId), "\"Fake\" Inbox", 3) }; - }); + []() -> std::vector> { + ++_getAppointmentsCount; + return { std::make_shared(response::IdType(_fakeAppointmentId), + "tomorrow", + "Lunch?", + false) }; + }, + []() -> std::vector> { + ++_getTasksCount; + return { std::make_shared(response::IdType(_fakeTaskId), + "Don't forget", + true) }; + }, + []() -> std::vector> { + ++_getUnreadCountsCount; + return { std::make_shared(response::IdType(_fakeFolderId), + "\"Fake\" Inbox", + 3) }; + }); auto mutation = std::make_shared( - [](today::CompleteTaskInput&& input) -> std::shared_ptr - { - return std::make_shared( - std::make_shared(std::move(input.id), "Mutated Task!", *(input.isComplete)), - std::move(input.clientMutationId) - ); - }); + [](today::CompleteTaskInput&& input) -> std::shared_ptr { + return std::make_shared( + std::make_shared(std::move(input.id), + "Mutated Task!", + *(input.isComplete)), + std::move(input.clientMutationId)); + }); auto subscription = std::make_shared( - [](const std::shared_ptr&) -> std::shared_ptr - { - return { std::make_shared(response::IdType(_fakeAppointmentId), "tomorrow", "Lunch?", true) }; - }); + [](const std::shared_ptr&) + -> std::shared_ptr { + return { std::make_shared(response::IdType(_fakeAppointmentId), + "tomorrow", + "Lunch?", + true) }; + }); _service = std::make_shared(query, mutation, subscription); } @@ -134,13 +142,21 @@ TEST_F(NoIntrospectionServiceCase, QueryEverything) })"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(1); - auto result = _service->resolve(std::launch::async, state, query, "Everything", std::move(variables)).get(); - EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; - EXPECT_EQ(size_t(1), _getTasksCount) << "today service lazy loads the tasks and caches the result"; - EXPECT_EQ(size_t(1), _getUnreadCountsCount) << "today service lazy loads the unreadCounts and caches the result"; - EXPECT_EQ(size_t(1), state->appointmentsRequestId) << "today service passed the same RequestState"; + auto result = + _service->resolve( + { query, "Everything"sv, std::move(variables), std::launch::async, state }) + .get(); + EXPECT_EQ(size_t(1), _getAppointmentsCount) + << "today service lazy loads the appointments and caches the result"; + EXPECT_EQ(size_t(1), _getTasksCount) + << "today service lazy loads the tasks and caches the result"; + EXPECT_EQ(size_t(1), _getUnreadCountsCount) + << "today service lazy loads the unreadCounts and caches the result"; + EXPECT_EQ(size_t(1), state->appointmentsRequestId) + << "today service passed the same RequestState"; EXPECT_EQ(size_t(1), state->tasksRequestId) << "today service passed the same RequestState"; - EXPECT_EQ(size_t(1), state->unreadCountsRequestId) << "today service passed the same RequestState"; + EXPECT_EQ(size_t(1), state->unreadCountsRequestId) + << "today service passed the same RequestState"; EXPECT_EQ(size_t(1), state->loadAppointmentsCount) << "today service called the loader once"; EXPECT_EQ(size_t(1), state->loadTasksCount) << "today service called the loader once"; EXPECT_EQ(size_t(1), state->loadUnreadCountsCount) << "today service called the loader once"; @@ -156,37 +172,55 @@ TEST_F(NoIntrospectionServiceCase, QueryEverything) const auto data = service::ScalarArgument::require("data", result); const auto appointments = service::ScalarArgument::require("appointments", data); - const auto appointmentEdges = service::ScalarArgument::require("edges", appointments); + const auto appointmentEdges = + service::ScalarArgument::require("edges", appointments); ASSERT_EQ(1, appointmentEdges.size()) << "appointments should have 1 entry"; - ASSERT_TRUE(appointmentEdges[0].type() == response::Type::Map) << "appointment should be an object"; + ASSERT_TRUE(appointmentEdges[0].type() == response::Type::Map) + << "appointment should be an object"; const auto appointmentNode = service::ScalarArgument::require("node", appointmentEdges[0]); - EXPECT_EQ(_fakeAppointmentId, service::IdArgument::require("id", appointmentNode)) << "id should match in base64 encoding"; - EXPECT_EQ("Lunch?", service::StringArgument::require("subject", appointmentNode)) << "subject should match"; - EXPECT_EQ("tomorrow", service::StringArgument::require("when", appointmentNode)) << "when should match"; - EXPECT_FALSE(service::BooleanArgument::require("isNow", appointmentNode)) << "isNow should match"; - EXPECT_EQ("Appointment", service::StringArgument::require("__typename", appointmentNode)) << "__typename should match"; + EXPECT_EQ(_fakeAppointmentId, service::IdArgument::require("id", appointmentNode)) + << "id should match in base64 encoding"; + EXPECT_EQ("Lunch?", service::StringArgument::require("subject", appointmentNode)) + << "subject should match"; + EXPECT_EQ("tomorrow", service::StringArgument::require("when", appointmentNode)) + << "when should match"; + EXPECT_FALSE(service::BooleanArgument::require("isNow", appointmentNode)) + << "isNow should match"; + EXPECT_EQ("Appointment", service::StringArgument::require("__typename", appointmentNode)) + << "__typename should match"; const auto tasks = service::ScalarArgument::require("tasks", data); - const auto taskEdges = service::ScalarArgument::require("edges", tasks); + const auto taskEdges = + service::ScalarArgument::require("edges", tasks); ASSERT_EQ(1, taskEdges.size()) << "tasks should have 1 entry"; ASSERT_TRUE(taskEdges[0].type() == response::Type::Map) << "task should be an object"; const auto taskNode = service::ScalarArgument::require("node", taskEdges[0]); - EXPECT_EQ(_fakeTaskId, service::IdArgument::require("id", taskNode)) << "id should match in base64 encoding"; - EXPECT_EQ("Don't forget", service::StringArgument::require("title", taskNode)) << "title should match"; - EXPECT_TRUE(service::BooleanArgument::require("isComplete", taskNode)) << "isComplete should match"; - EXPECT_EQ("Task", service::StringArgument::require("__typename", taskNode)) << "__typename should match"; + EXPECT_EQ(_fakeTaskId, service::IdArgument::require("id", taskNode)) + << "id should match in base64 encoding"; + EXPECT_EQ("Don't forget", service::StringArgument::require("title", taskNode)) + << "title should match"; + EXPECT_TRUE(service::BooleanArgument::require("isComplete", taskNode)) + << "isComplete should match"; + EXPECT_EQ("Task", service::StringArgument::require("__typename", taskNode)) + << "__typename should match"; const auto unreadCounts = service::ScalarArgument::require("unreadCounts", data); - const auto unreadCountEdges = service::ScalarArgument::require("edges", unreadCounts); + const auto unreadCountEdges = + service::ScalarArgument::require("edges", unreadCounts); ASSERT_EQ(1, unreadCountEdges.size()) << "unreadCounts should have 1 entry"; - ASSERT_TRUE(unreadCountEdges[0].type() == response::Type::Map) << "unreadCount should be an object"; + ASSERT_TRUE(unreadCountEdges[0].type() == response::Type::Map) + << "unreadCount should be an object"; const auto unreadCountNode = service::ScalarArgument::require("node", unreadCountEdges[0]); - EXPECT_EQ(_fakeFolderId, service::IdArgument::require("id", unreadCountNode)) << "id should match in base64 encoding"; - EXPECT_EQ("\"Fake\" Inbox", service::StringArgument::require("name", unreadCountNode)) << "name should match"; - EXPECT_EQ(3, service::IntArgument::require("unreadCount", unreadCountNode)) << "unreadCount should match"; - EXPECT_EQ("Folder", service::StringArgument::require("__typename", unreadCountNode)) << "__typename should match"; + EXPECT_EQ(_fakeFolderId, service::IdArgument::require("id", unreadCountNode)) + << "id should match in base64 encoding"; + EXPECT_EQ("\"Fake\" Inbox", service::StringArgument::require("name", unreadCountNode)) + << "name should match"; + EXPECT_EQ(3, service::IntArgument::require("unreadCount", unreadCountNode)) + << "unreadCount should match"; + EXPECT_EQ("Folder", service::StringArgument::require("__typename", unreadCountNode)) + << "__typename should match"; } - catch (service::schema_exception & ex) + catch (service::schema_exception& ex) { FAIL() << response::toJSON(ex.getErrors()); } @@ -199,9 +233,7 @@ TEST_F(NoIntrospectionServiceCase, NoSchema) queryType { name } } })"_graphql; - response::Value variables(response::Type::Map); - auto future = _service->resolve(std::launch::deferred, nullptr, query, "", std::move(variables)); - auto result = future.get(); + auto result = _service->resolve({ query }).get(); try { @@ -209,9 +241,12 @@ TEST_F(NoIntrospectionServiceCase, NoSchema) auto errorsItr = result.find("errors"); ASSERT_FALSE(errorsItr == result.get().cend()); auto errorsString = response::toJSON(response::Value(errorsItr->second)); - EXPECT_EQ(R"js([{"message":"Undefined field type: Query name: __schema","locations":[{"line":2,"column":4}]}])js", errorsString) << "error should match"; + EXPECT_EQ( + R"js([{"message":"Undefined field type: Query name: __schema","locations":[{"line":2,"column":4}]}])js", + errorsString) + << "error should match"; } - catch (service::schema_exception & ex) + catch (service::schema_exception& ex) { FAIL() << response::toJSON(ex.getErrors()); } @@ -224,9 +259,7 @@ TEST_F(NoIntrospectionServiceCase, NoType) description } })"_graphql; - response::Value variables(response::Type::Map); - auto future = _service->resolve(std::launch::deferred, nullptr, query, "", std::move(variables)); - auto result = future.get(); + auto result = _service->resolve({ query }).get(); try { @@ -234,9 +267,12 @@ TEST_F(NoIntrospectionServiceCase, NoType) auto errorsItr = result.find("errors"); ASSERT_FALSE(errorsItr == result.get().cend()); auto errorsString = response::toJSON(response::Value(errorsItr->second)); - EXPECT_EQ(R"js([{"message":"Undefined field type: Query name: __type","locations":[{"line":2,"column":4}]}])js", errorsString) << "error should match"; + EXPECT_EQ( + R"js([{"message":"Undefined field type: Query name: __type","locations":[{"line":2,"column":4}]}])js", + errorsString) + << "error should match"; } - catch (service::schema_exception & ex) + catch (service::schema_exception& ex) { FAIL() << response::toJSON(ex.getErrors()); } diff --git a/test/ResponseTests.cpp b/test/ResponseTests.cpp index a035d97a..0a878a58 100644 --- a/test/ResponseTests.cpp +++ b/test/ResponseTests.cpp @@ -13,5 +13,5 @@ TEST(ResponseCase, ValueConstructorFromStringLiteral) auto actual = response::Value(expected); ASSERT_TRUE(response::Type::String == actual.type()); - ASSERT_EQ(expected, actual.release()); + ASSERT_EQ(expected, actual.release()); } diff --git a/test/TodayTests.cpp b/test/TodayTests.cpp index 246f9579..8130f23b 100644 --- a/test/TodayTests.cpp +++ b/test/TodayTests.cpp @@ -137,7 +137,8 @@ TEST_F(TodayServiceCase, QueryEverything) response::Value variables(response::Type::Map); auto state = std::make_shared(1); auto result = - _service->resolve(std::launch::async, state, query, "Everything", std::move(variables)) + _service->resolve( + { query, "Everything"sv, std::move(variables), std::launch::async, state }) .get(); EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; @@ -235,7 +236,7 @@ TEST_F(TodayServiceCase, QueryAppointments) })"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(2); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; EXPECT_GE(size_t(1), _getTasksCount) @@ -300,7 +301,7 @@ TEST_F(TodayServiceCase, QueryAppointmentsWithForceError) })"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(2); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; EXPECT_GE(size_t(1), _getTasksCount) @@ -373,7 +374,7 @@ TEST_F(TodayServiceCase, QueryAppointmentsWithForceErrorAsync) response::Value variables(response::Type::Map); auto state = std::make_shared(2); auto result = - _service->resolve(std::launch::async, state, query, "", std::move(variables)).get(); + _service->resolve({ query, {}, std::move(variables), std::launch::async, state }).get(); EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; EXPECT_GE(size_t(1), _getTasksCount) @@ -443,7 +444,7 @@ TEST_F(TodayServiceCase, QueryTasks) })gql"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(3); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); EXPECT_GE(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; EXPECT_EQ(size_t(1), _getTasksCount) @@ -501,7 +502,7 @@ TEST_F(TodayServiceCase, QueryUnreadCounts) })"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(4); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); EXPECT_GE(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; EXPECT_GE(size_t(1), _getTasksCount) @@ -560,7 +561,7 @@ TEST_F(TodayServiceCase, MutateCompleteTask) })"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(5); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); try { @@ -607,15 +608,18 @@ TEST_F(TodayServiceCase, SubscribeNextAppointmentChangeDefault) response::Value variables(response::Type::Map); auto state = std::make_shared(6); response::Value result; - auto key = _service->subscribe(service::SubscriptionParams { state, - std::move(query), - "TestSubscription", - std::move(std::move(variables)) }, - [&result](std::future response) { - result = response.get(); - }); - _service->deliver("nextAppointmentChange", nullptr); - _service->unsubscribe(key); + auto key = _service + ->subscribe({ [&result](response::Value&& response) { + result = std::move(response); + }, + std::move(query), + "TestSubscription"s, + std::move(variables), + {}, + state }) + .get(); + _service->deliver({ "nextAppointmentChange"sv }).get(); + _service->unsubscribe({ key }).get(); try { @@ -667,16 +671,23 @@ TEST_F(TodayServiceCase, SubscribeNextAppointmentChangeOverride) true); }); response::Value result; - auto key = _service->subscribe(service::SubscriptionParams { state, - std::move(query), - "TestSubscription", - std::move(std::move(variables)) }, - [&result](std::future response) { - result = response.get(); - }); - _service->deliver("nextAppointmentChange", - std::static_pointer_cast(subscriptionObject)); - _service->unsubscribe(key); + auto key = _service + ->subscribe({ [&result](response::Value&& response) { + result = std::move(response); + }, + std::move(query), + "TestSubscription"s, + std::move(variables), + {}, + state }) + .get(); + _service + ->deliver({ "nextAppointmentChange"sv, + {}, // filter + {}, // launch + std::make_shared(std::move(subscriptionObject)) }) + .get(); + _service->unsubscribe({ key }).get(); try { @@ -712,7 +723,7 @@ TEST_F(TodayServiceCase, DeliverNextAppointmentChangeNoSubscriptionObject) try { - service->deliver("nextAppointmentChange", nullptr); + service->deliver({ "nextAppointmentChange"sv }).get(); } catch (const std::invalid_argument& ex) { @@ -730,7 +741,7 @@ TEST_F(TodayServiceCase, DeliverNextAppointmentChangeNoSubscriptionSupport) try { - service->deliver("nextAppointmentChange", nullptr); + service->deliver({ "nextAppointmentChange"sv }).get(); } catch (const std::logic_error& ex) { @@ -779,7 +790,7 @@ TEST_F(TodayServiceCase, Introspection) response::Value variables(response::Type::Map); auto state = std::make_shared(8); auto result = - _service->resolve(std::launch::async, state, query, "", std::move(variables)).get(); + _service->resolve({ query, {}, std::move(variables), std::launch::async, state }).get(); try { @@ -844,7 +855,7 @@ TEST_F(TodayServiceCase, SkipDirective) })"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(9); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); try { @@ -909,7 +920,7 @@ TEST_F(TodayServiceCase, IncludeDirective) })"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(10); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); try { @@ -955,7 +966,7 @@ TEST_F(TodayServiceCase, NestedFragmentDirectives) inlineFragmentNested: nested @fieldTag(field: "nested3") { ...on NestedType @inlineFragmentTag(inlineFragment: "inlineFragment4") { ...on NestedType @inlineFragmentTag(inlineFragment: "inlineFragment5") { - inlineFragmentNested: nested @fieldTag(field: "nested4") { + inlineFragmentNested: nested @repeatableOnField @fieldTag(field: "nested4") @repeatableOnField { depth @fieldTag(field: "depth4") } } @@ -967,7 +978,7 @@ TEST_F(TodayServiceCase, NestedFragmentDirectives) })"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(11); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); try { @@ -995,61 +1006,107 @@ TEST_F(TodayServiceCase, NestedFragmentDirectives) capturedParams.pop(); const auto params1 = std::move(capturedParams.top()); capturedParams.pop(); - const auto queryTag1 = - service::ScalarArgument::require("queryTag", params1.operationDirectives); + ASSERT_EQ(size_t(1), params1.operationDirectives.size()) << "missing operation directive"; + const auto itrQueryTag1 = params1.operationDirectives.cbegin(); + ASSERT_TRUE(itrQueryTag1->first == "queryTag"sv) << "missing required directive"; + const auto& queryTag1 = itrQueryTag1->second; const auto query1 = service::StringArgument::require("query", queryTag1); const auto fragmentDefinitionCount1 = params1.fragmentDefinitionDirectives.size(); const auto fragmentSpreadCount1 = params1.fragmentSpreadDirectives.size(); const auto inlineFragmentCount1 = params1.inlineFragmentDirectives.size(); - const auto fieldTag1 = - service::ScalarArgument::require("fieldTag", params1.fieldDirectives); + ASSERT_EQ(size_t(1), params1.fieldDirectives.size()) << "missing operation directive"; + const auto itrFieldTag1 = params1.fieldDirectives.cbegin(); + ASSERT_TRUE(itrFieldTag1->first == "fieldTag"sv) << "missing required directive"; + const auto& fieldTag1 = itrFieldTag1->second; const auto field1 = service::StringArgument::require("field", fieldTag1); - const auto queryTag2 = - service::ScalarArgument::require("queryTag", params2.operationDirectives); + ASSERT_EQ(size_t(1), params2.operationDirectives.size()) << "missing operation directive"; + const auto itrQueryTag2 = params2.operationDirectives.cbegin(); + ASSERT_TRUE(itrQueryTag2->first == "queryTag"sv) << "missing required directive"; + const auto& queryTag2 = itrQueryTag2->second; const auto query2 = service::StringArgument::require("query", queryTag2); - const auto fragmentDefinitionTag2 = - service::ScalarArgument::require("fragmentDefinitionTag", - params2.fragmentDefinitionDirectives); + ASSERT_EQ(size_t(1), params2.fragmentDefinitionDirectives.size()) + << "missing fragment definition directive"; + const auto itrFragmentDefinitionTag2 = params2.fragmentDefinitionDirectives.cbegin(); + ASSERT_TRUE(itrFragmentDefinitionTag2->first == "fragmentDefinitionTag"sv) + << "missing fragment definition directive"; + const auto& fragmentDefinitionTag2 = itrFragmentDefinitionTag2->second; const auto fragmentDefinition2 = service::StringArgument::require("fragmentDefinition", fragmentDefinitionTag2); - const auto fragmentSpreadTag2 = - service::ScalarArgument::require("fragmentSpreadTag", params2.fragmentSpreadDirectives); + ASSERT_EQ(size_t(1), params2.fragmentSpreadDirectives.size()) + << "missing fragment spread directive"; + const auto itrFragmentSpreadTag2 = params2.fragmentSpreadDirectives.cbegin(); + ASSERT_TRUE(itrFragmentSpreadTag2->first == "fragmentSpreadTag"sv) + << "missing fragment spread directive"; + const auto& fragmentSpreadTag2 = itrFragmentSpreadTag2->second; const auto fragmentSpread2 = service::StringArgument::require("fragmentSpread", fragmentSpreadTag2); const auto inlineFragmentCount2 = params2.inlineFragmentDirectives.size(); - const auto fieldTag2 = - service::ScalarArgument::require("fieldTag", params2.fieldDirectives); + ASSERT_EQ(size_t(1), params2.fieldDirectives.size()) << "missing field directive"; + const auto itrFieldTag2 = params2.fieldDirectives.cbegin(); + ASSERT_TRUE(itrFieldTag2->first == "fieldTag"sv) << "missing field directive"; + const auto& fieldTag2 = itrFieldTag2->second; const auto field2 = service::StringArgument::require("field", fieldTag2); - const auto queryTag3 = - service::ScalarArgument::require("queryTag", params3.operationDirectives); + ASSERT_EQ(size_t(1), params3.operationDirectives.size()) << "missing operation directive"; + const auto itrQueryTag3 = params3.operationDirectives.cbegin(); + ASSERT_TRUE(itrQueryTag3->first == "queryTag"sv) << "missing required directive"; + const auto& queryTag3 = itrQueryTag3->second; const auto query3 = service::StringArgument::require("query", queryTag3); - const auto fragmentDefinitionTag3 = - service::ScalarArgument::require("fragmentDefinitionTag", - params3.fragmentDefinitionDirectives); + ASSERT_EQ(size_t(1), params3.fragmentDefinitionDirectives.size()) + << "missing fragment definition directive"; + const auto itrFragmentDefinitionTag3 = params3.fragmentDefinitionDirectives.cbegin(); + ASSERT_TRUE(itrFragmentDefinitionTag3->first == "fragmentDefinitionTag"sv) + << "missing fragment definition directive"; + const auto& fragmentDefinitionTag3 = itrFragmentDefinitionTag3->second; const auto fragmentDefinition3 = service::StringArgument::require("fragmentDefinition", fragmentDefinitionTag3); - const auto fragmentSpreadTag3 = - service::ScalarArgument::require("fragmentSpreadTag", params3.fragmentSpreadDirectives); + ASSERT_EQ(size_t(1), params3.fragmentSpreadDirectives.size()) + << "missing fragment spread directive"; + const auto itrFragmentSpreadTag3 = params3.fragmentSpreadDirectives.cbegin(); + ASSERT_TRUE(itrFragmentSpreadTag3->first == "fragmentSpreadTag"sv) + << "missing fragment spread directive"; + const auto& fragmentSpreadTag3 = itrFragmentSpreadTag3->second; const auto fragmentSpread3 = service::StringArgument::require("fragmentSpread", fragmentSpreadTag3); - const auto inlineFragmentTag3 = - service::ScalarArgument::require("inlineFragmentTag", params3.inlineFragmentDirectives); + ASSERT_EQ(size_t(1), params3.inlineFragmentDirectives.size()) + << "missing inline fragment directive"; + const auto itrInlineFragmentTag3 = params3.inlineFragmentDirectives.cbegin(); + ASSERT_TRUE(itrInlineFragmentTag3->first == "inlineFragmentTag"sv); + const auto& inlineFragmentTag3 = itrInlineFragmentTag3->second; const auto inlineFragment3 = service::StringArgument::require("inlineFragment", inlineFragmentTag3); - const auto fieldTag3 = - service::ScalarArgument::require("fieldTag", params3.fieldDirectives); + ASSERT_EQ(size_t(1), params3.fieldDirectives.size()) << "missing field directive"; + const auto itrFieldTag3 = params3.fieldDirectives.cbegin(); + ASSERT_TRUE(itrFieldTag3->first == "fieldTag"sv) << "missing field directive"; + const auto& fieldTag3 = itrFieldTag3->second; const auto field3 = service::StringArgument::require("field", fieldTag3); - const auto queryTag4 = - service::ScalarArgument::require("queryTag", params4.operationDirectives); + ASSERT_EQ(size_t(1), params4.operationDirectives.size()) << "missing operation directive"; + const auto itrQueryTag4 = params4.operationDirectives.cbegin(); + ASSERT_TRUE(itrQueryTag4->first == "queryTag"sv) << "missing required directive"; + const auto& queryTag4 = itrQueryTag4->second; const auto query4 = service::StringArgument::require("query", queryTag4); const auto fragmentDefinitionCount4 = params4.fragmentDefinitionDirectives.size(); const auto fragmentSpreadCount4 = params4.fragmentSpreadDirectives.size(); - const auto inlineFragmentTag4 = - service::ScalarArgument::require("inlineFragmentTag", params4.inlineFragmentDirectives); + ASSERT_EQ(size_t(1), params4.inlineFragmentDirectives.size()) + << "missing inline fragment directive"; + const auto itrInlineFragmentTag4 = params4.inlineFragmentDirectives.cbegin(); + ASSERT_TRUE(itrInlineFragmentTag4->first == "inlineFragmentTag"sv); + const auto& inlineFragmentTag4 = itrInlineFragmentTag4->second; const auto inlineFragment4 = service::StringArgument::require("inlineFragment", inlineFragmentTag4); - const auto fieldTag4 = - service::ScalarArgument::require("fieldTag", params4.fieldDirectives); + ASSERT_EQ(size_t(3), params4.fieldDirectives.size()) << "missing field directive"; + const auto itrRepeatable1 = params4.fieldDirectives.cbegin(); + ASSERT_TRUE(itrRepeatable1->first == "repeatableOnField"sv) << "missing field directive"; + EXPECT_TRUE(response::Type::Map == itrRepeatable1->second.type()) + << "unexpected arguments type directive"; + EXPECT_EQ(size_t(0), itrRepeatable1->second.size()) << "extra arguments on directive"; + const auto itrFieldTag4 = itrRepeatable1 + 1; + ASSERT_TRUE(itrFieldTag4->first == "fieldTag"sv) << "missing field directive"; + const auto& fieldTag4 = itrFieldTag4->second; + const auto itrRepeatable2 = itrFieldTag4 + 1; + ASSERT_TRUE(itrRepeatable2->first == "repeatableOnField"sv) << "missing field directive"; + EXPECT_TRUE(response::Type::Map == itrRepeatable2->second.type()) + << "unexpected arguments type directive"; + EXPECT_EQ(size_t(0), itrRepeatable2->second.size()) << "extra arguments on directive"; const auto field4 = service::StringArgument::require("field", fieldTag4); ASSERT_EQ(1, depth1); @@ -1079,9 +1136,11 @@ TEST_F(TodayServiceCase, NestedFragmentDirectives) ASSERT_EQ("nested3", field3) << "remember the field directives"; ASSERT_EQ("nested", query4) << "remember the operation directives"; ASSERT_EQ(size_t(0), fragmentDefinitionCount4) - << "traversing a field to a nested object SelectionSet resets the fragment directives"; + << "traversing a field to a nested object SelectionSet resets the fragment " + "directives"; ASSERT_EQ(size_t(0), fragmentSpreadCount4) - << "traversing a field to a nested object SelectionSet resets the fragment directives"; + << "traversing a field to a nested object SelectionSet resets the fragment " + "directives"; ASSERT_EQ("inlineFragment5", inlineFragment4) << "nested inline fragments don't reset, but do overwrite on collision"; ASSERT_EQ("nested4", field4) << "remember the field directives"; @@ -1103,10 +1162,9 @@ TEST_F(TodayServiceCase, QueryAppointmentsById) } })"_graphql; response::Value variables(response::Type::Map); - variables.emplace_back("appointmentId", - response::Value(std::string("ZmFrZUFwcG9pbnRtZW50SWQ="))); + variables.emplace_back("appointmentId", response::Value("ZmFrZUFwcG9pbnRtZW50SWQ="s)); auto state = std::make_shared(12); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; EXPECT_GE(size_t(1), _getTasksCount) @@ -1156,8 +1214,7 @@ TEST_F(TodayServiceCase, UnimplementedFieldError) auto query = R"(query { unimplemented })"_graphql; - response::Value variables(response::Type::Map); - auto result = _service->resolve(nullptr, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query }).get(); try { @@ -1192,25 +1249,34 @@ TEST_F(TodayServiceCase, SubscribeNodeChangeMatchingId) auto state = std::make_shared(13); auto subscriptionObject = std::make_shared( [this](const std::shared_ptr& state, - response::IdType&& idArg) -> std::shared_ptr { + response::IdType&& idArg) -> std::shared_ptr { EXPECT_EQ(13, std::static_pointer_cast(state)->requestId) << "should pass the RequestState to the subscription resolvers"; EXPECT_EQ(_fakeTaskId, idArg); - return std::static_pointer_cast( - std::make_shared(response::IdType(_fakeTaskId), "Don't forget", true)); + return std::make_shared(std::make_shared( + std::make_shared(response::IdType(_fakeTaskId), + "Don't forget", + true))); }); response::Value result; - auto key = _service->subscribe(service::SubscriptionParams { state, - std::move(query), - "TestSubscription", - std::move(std::move(variables)) }, - [&result](std::future response) { - result = response.get(); - }); - _service->deliver("nodeChange", - { { "id", response::Value(std::string("ZmFrZVRhc2tJZA==")) } }, - std::static_pointer_cast(subscriptionObject)); - _service->unsubscribe(key); + auto key = _service + ->subscribe({ [&result](response::Value&& response) { + result = std::move(response); + }, + std::move(query), + "TestSubscription", + std::move(variables), + {}, + state }) + .get(); + _service + ->deliver({ "nodeChange"sv, + { service::SubscriptionFilter { { service::SubscriptionArguments { + { "id", response::Value("ZmFrZVRhc2tJZA=="s) } } } } }, + {}, // launch + std::make_shared(std::move(subscriptionObject)) }) + .get(); + _service->unsubscribe({ key }).get(); try { @@ -1251,22 +1317,27 @@ TEST_F(TodayServiceCase, SubscribeNodeChangeMismatchedId) bool calledResolver = false; auto subscriptionObject = std::make_shared( [this, &calledResolver](const std::shared_ptr& state, - response::IdType&& idArg) -> std::shared_ptr { + response::IdType&& idArg) -> std::shared_ptr { calledResolver = true; return nullptr; }); bool calledGet = false; - auto key = _service->subscribe(service::SubscriptionParams { nullptr, - std::move(query), - "TestSubscription", - std::move(std::move(variables)) }, - [&calledGet](std::future) { - calledGet = true; - }); - _service->deliver("nodeChange", - { { "id", response::Value(std::string("ZmFrZUFwcG9pbnRtZW50SWQ=")) } }, - std::static_pointer_cast(subscriptionObject)); - _service->unsubscribe(key); + auto key = _service + ->subscribe({ [&calledGet](response::Value&&) { + calledGet = true; + }, + std::move(query), + "TestSubscription"s, + std::move(variables) }) + .get(); + _service + ->deliver({ "nodeChange"sv, + { service::SubscriptionFilter { { service::SubscriptionArguments { + { "id", response::Value("ZmFrZUFwcG9pbnRtZW50SWQ="s) } } } } }, + {}, // launch + std::make_shared(std::move(subscriptionObject)) }) + .get(); + _service->unsubscribe({ key }).get(); try { @@ -1297,33 +1368,42 @@ TEST_F(TodayServiceCase, SubscribeNodeChangeFuzzyComparator) response::MapType::const_reference fuzzy) noexcept -> bool { EXPECT_FALSE(filterCalled); EXPECT_EQ("id", fuzzy.first) << "should only get called once for the id argument"; - EXPECT_EQ("ZmFr", fuzzy.second.get()); + EXPECT_EQ("ZmFr", fuzzy.second.get()); filterCalled = true; return true; }; auto subscriptionObject = std::make_shared( [this](const std::shared_ptr& state, - response::IdType&& idArg) -> std::shared_ptr { + response::IdType&& idArg) -> std::shared_ptr { const response::IdType fuzzyId { 'f', 'a', 'k' }; EXPECT_EQ(14, std::static_pointer_cast(state)->requestId) << "should pass the RequestState to the subscription resolvers"; EXPECT_EQ(fuzzyId, idArg); - return std::static_pointer_cast( - std::make_shared(response::IdType(_fakeTaskId), "Don't forget", true)); + return std::make_shared(std::make_shared( + std::make_shared(response::IdType(_fakeTaskId), + "Don't forget", + true))); }); response::Value result; - auto key = _service->subscribe(service::SubscriptionParams { state, - std::move(query), - "TestSubscription", - std::move(std::move(variables)) }, - [&result](std::future response) { - result = response.get(); - }); - _service->deliver("nodeChange", - filterCallback, - std::static_pointer_cast(subscriptionObject)); - _service->unsubscribe(key); + auto key = _service + ->subscribe({ [&result](response::Value&& response) { + result = std::move(response); + }, + std::move(query), + "TestSubscription"s, + std::move(variables), + {}, + state }) + .get(); + _service + ->deliver({ "nodeChange"sv, + { service::SubscriptionFilter { + { service::SubscriptionArgumentFilterCallback { std::move(filterCallback) } } } }, + {}, // launch + std::make_shared(std::move(subscriptionObject)) }) + .get(); + _service->unsubscribe({ key }).get(); try { @@ -1367,29 +1447,34 @@ TEST_F(TodayServiceCase, SubscribeNodeChangeFuzzyMismatch) response::MapType::const_reference fuzzy) noexcept -> bool { EXPECT_FALSE(filterCalled); EXPECT_EQ("id", fuzzy.first) << "should only get called once for the id argument"; - EXPECT_EQ("ZmFrZVRhc2tJZA==", fuzzy.second.get()); + EXPECT_EQ("ZmFrZVRhc2tJZA==", fuzzy.second.get()); filterCalled = true; return false; }; bool calledResolver = false; auto subscriptionObject = std::make_shared( [this, &calledResolver](const std::shared_ptr& state, - response::IdType&& idArg) -> std::shared_ptr { + response::IdType&& idArg) -> std::shared_ptr { calledResolver = true; return nullptr; }); bool calledGet = false; - auto key = _service->subscribe(service::SubscriptionParams { nullptr, - std::move(query), - "TestSubscription", - std::move(std::move(variables)) }, - [&calledGet](std::future) { - calledGet = true; - }); - _service->deliver("nodeChange", - filterCallback, - std::static_pointer_cast(subscriptionObject)); - _service->unsubscribe(key); + auto key = _service + ->subscribe({ [&calledGet](response::Value&&) { + calledGet = true; + }, + std::move(query), + "TestSubscription"s, + std::move(variables) }) + .get(); + _service + ->deliver({ "nodeChange"sv, + { service::SubscriptionFilter { + { service::SubscriptionArgumentFilterCallback { std::move(filterCallback) } } } }, + {}, // launch + std::make_shared(std::move(subscriptionObject)) }) + .get(); + _service->unsubscribe({ key }).get(); try { @@ -1415,29 +1500,38 @@ TEST_F(TodayServiceCase, SubscribeNodeChangeMatchingVariable) } })"); response::Value variables(response::Type::Map); - variables.emplace_back("taskId", response::Value(std::string("ZmFrZVRhc2tJZA=="))); + variables.emplace_back("taskId", response::Value("ZmFrZVRhc2tJZA=="s)); auto state = std::make_shared(14); auto subscriptionObject = std::make_shared( [this](const std::shared_ptr& state, - response::IdType&& idArg) -> std::shared_ptr { + response::IdType&& idArg) -> std::shared_ptr { EXPECT_EQ(14, std::static_pointer_cast(state)->requestId) << "should pass the RequestState to the subscription resolvers"; EXPECT_EQ(_fakeTaskId, idArg); - return std::static_pointer_cast( - std::make_shared(response::IdType(_fakeTaskId), "Don't forget", true)); + return std::make_shared(std::make_shared( + std::make_shared(response::IdType(_fakeTaskId), + "Don't forget", + true))); }); response::Value result; - auto key = _service->subscribe(service::SubscriptionParams { state, - std::move(query), - "TestSubscription", - std::move(std::move(variables)) }, - [&result](std::future response) { - result = response.get(); - }); - _service->deliver("nodeChange", - { { "id", response::Value(std::string("ZmFrZVRhc2tJZA==")) } }, - std::static_pointer_cast(subscriptionObject)); - _service->unsubscribe(key); + auto key = _service + ->subscribe({ [&result](response::Value&& response) { + result = std::move(response); + }, + std::move(query), + "TestSubscription", + std::move(variables), + {}, + state }) + .get(); + _service + ->deliver({ "nodeChange"sv, + { service::SubscriptionFilter { { service::SubscriptionArguments { + { "id", response::Value("ZmFrZVRhc2tJZA=="s) } } } } }, + {}, // launch + std::make_shared(std::move(subscriptionObject)) }) + .get(); + _service->unsubscribe({ key }).get(); try { @@ -1474,18 +1568,9 @@ TEST_F(TodayServiceCase, DeferredQueryAppointmentsById) } })"_graphql; response::Value variables(response::Type::Map); - variables.emplace_back("appointmentId", - response::Value(std::string("ZmFrZUFwcG9pbnRtZW50SWQ="))); + variables.emplace_back("appointmentId", response::Value("ZmFrZUFwcG9pbnRtZW50SWQ="s)); auto state = std::make_shared(15); - auto future = _service->resolve(std::launch::deferred, state, query, "", std::move(variables)); - ASSERT_EQ(std::future_status::deferred, future.wait_for(0s)) << "should be deferred"; - EXPECT_EQ(size_t(0), state->loadAppointmentsCount) - << "today service should not call the loader until we block"; - ASSERT_EQ(std::future_status::deferred, future.wait_for(0s)) - << "should stay deferred until we block"; - EXPECT_EQ(size_t(0), state->loadAppointmentsCount) - << "today service should not call the loader until we block"; - auto result = future.get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; EXPECT_GE(size_t(1), _getTasksCount) @@ -1541,12 +1626,10 @@ TEST_F(TodayServiceCase, NonBlockingQueryAppointmentsById) } })"_graphql; response::Value variables(response::Type::Map); - variables.emplace_back("appointmentId", - response::Value(std::string("ZmFrZUFwcG9pbnRtZW50SWQ="))); + variables.emplace_back("appointmentId", response::Value("ZmFrZUFwcG9pbnRtZW50SWQ="s)); auto state = std::make_shared(16); - auto future = _service->resolve(std::launch::async, state, query, "", std::move(variables)); - ASSERT_NE(std::future_status::deferred, future.wait_for(0s)) << "should not start out deferred"; - auto result = future.get(); + auto result = + _service->resolve({ query, {}, std::move(variables), std::launch::async, state }).get(); EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; EXPECT_GE(size_t(1), _getTasksCount) @@ -1598,10 +1681,7 @@ TEST_F(TodayServiceCase, NonExistentTypeIntrospection) description } })"_graphql; - response::Value variables(response::Type::Map); - auto future = - _service->resolve(std::launch::deferred, nullptr, query, "", std::move(variables)); - auto result = future.get(); + auto result = _service->resolve({ query }).get(); try { @@ -1633,15 +1713,18 @@ TEST_F(TodayServiceCase, SubscribeNextAppointmentChangeAsync) response::Value variables(response::Type::Map); auto state = std::make_shared(17); response::Value result; - auto key = _service->subscribe(service::SubscriptionParams { state, - std::move(query), - "TestSubscription", - std::move(std::move(variables)) }, - [&result](std::future response) { - result = response.get(); - }); - _service->deliver(std::launch::async, "nextAppointmentChange", nullptr); - _service->unsubscribe(key); + auto key = _service + ->subscribe({ [&result](response::Value&& response) { + result = std::move(response); + }, + std::move(query), + "TestSubscription"s, + std::move(variables), + {}, + state }) + .get(); + _service->deliver({ "nextAppointmentChange"sv, {}, std::launch::async }).get(); + _service->unsubscribe({ key }).get(); try { @@ -1680,12 +1763,10 @@ TEST_F(TodayServiceCase, NonblockingDeferredExpensive) response::Value variables(response::Type::Map); auto state = std::make_shared(18); std::unique_lock testLock(today::Expensive::testMutex); - auto future = _service->resolve(std::launch::deferred, - state, - query, - "NonblockingDeferredExpensive", - std::move(variables)); - auto result = future.get(); + auto result = + _service + ->resolve({ query, "NonblockingDeferredExpensive"sv, std::move(variables), {}, state }) + .get(); try { @@ -1715,12 +1796,13 @@ TEST_F(TodayServiceCase, BlockingAsyncExpensive) response::Value variables(response::Type::Map); auto state = std::make_shared(19); std::unique_lock testLock(today::Expensive::testMutex); - auto future = _service->resolve(std::launch::async, - state, - query, - "BlockingAsyncExpensive", - std::move(variables)); - auto result = future.get(); + auto result = _service + ->resolve({ query, + "BlockingAsyncExpensive"sv, + std::move(variables), + std::launch::async, + state }) + .get(); try { @@ -1762,7 +1844,7 @@ TEST_F(TodayServiceCase, QueryAppointmentsThroughUnionTypeFragment) })"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(20); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; EXPECT_GE(size_t(1), _getTasksCount) @@ -1833,15 +1915,19 @@ TEST_F(TodayServiceCase, SubscribeUnsubscribeNotificationsAsync) today::NextAppointmentChange::getCount(service::ResolverContext::Subscription); const auto notifyUnsubscribeBegin = today::NextAppointmentChange::getCount(service::ResolverContext::NotifyUnsubscribe); - auto key = _service->subscribe(std::launch::async, - service::SubscriptionParams { state, - std::move(query), - "TestSubscription", - std::move(std::move(variables)) }, - [&calledCallback](std::future response) { - calledCallback = true; - }); - _service->unsubscribe(std::launch::async, key.get()).get(); + auto key = _service + ->subscribe({ + [&calledCallback](response::Value&& response) { + calledCallback = true; + }, + std::move(query), + "TestSubscription"s, + std::move(variables), + std::launch::async, + state, + }) + .get(); + _service->unsubscribe({ key, std::launch::async }).get(); const auto notifySubscribeEnd = today::NextAppointmentChange::getCount(service::ResolverContext::NotifySubscribe); const auto subscriptionEnd = @@ -1883,15 +1969,17 @@ TEST_F(TodayServiceCase, SubscribeUnsubscribeNotificationsDeferred) today::NextAppointmentChange::getCount(service::ResolverContext::Subscription); const auto notifyUnsubscribeBegin = today::NextAppointmentChange::getCount(service::ResolverContext::NotifyUnsubscribe); - auto key = _service->subscribe(std::launch::deferred, - service::SubscriptionParams { state, - std::move(query), - "TestSubscription", - std::move(std::move(variables)) }, - [&calledCallback](std::future response) { - calledCallback = true; - }); - _service->unsubscribe(std::launch::deferred, key.get()).get(); + auto key = _service + ->subscribe({ [&calledCallback](response::Value&& response) { + calledCallback = true; + }, + std::move(query), + "TestSubscription"s, + std::move(variables), + {}, + state }) + .get(); + _service->unsubscribe({ key }).get(); const auto notifySubscribeEnd = today::NextAppointmentChange::getCount(service::ResolverContext::NotifySubscribe); const auto subscriptionEnd = @@ -1921,7 +2009,7 @@ TEST_F(TodayServiceCase, MutateSetFloat) })"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(22); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); try { @@ -1951,7 +2039,7 @@ TEST_F(TodayServiceCase, MutateCoerceSetFloat) })"_graphql; response::Value variables(response::Type::Map); auto state = std::make_shared(22); - auto result = _service->resolve(state, query, "", std::move(variables)).get(); + auto result = _service->resolve({ query, {}, std::move(variables), {}, state }).get(); try { diff --git a/test/ValidationTests.cpp b/test/ValidationTests.cpp index 071e9317..e14aa1fa 100644 --- a/test/ValidationTests.cpp +++ b/test/ValidationTests.cpp @@ -34,9 +34,9 @@ class ValidationExamplesCase : public ::testing::Test std::shared_ptr ValidationExamplesCase::_service; -TEST_F(ValidationExamplesCase, CounterExample91) +TEST_F(ValidationExamplesCase, CounterExample102) { - // http://spec.graphql.org/June2018/#example-12752 + // https://spec.graphql.org/October2021/#example-12752 auto query = R"(query getDogName { dog { name @@ -61,9 +61,9 @@ TEST_F(ValidationExamplesCase, CounterExample91) << "error should match"; } -TEST_F(ValidationExamplesCase, Example92) +TEST_F(ValidationExamplesCase, Example103) { - // http://spec.graphql.org/June2018/#example-069e1 + // https://spec.graphql.org/October2021/#example-069e1 auto query = R"(query getDogName { dog { name @@ -83,9 +83,9 @@ TEST_F(ValidationExamplesCase, Example92) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample93) +TEST_F(ValidationExamplesCase, CounterExample104) { - // http://spec.graphql.org/June2018/#example-5e409 + // https://spec.graphql.org/October2021/#example-5e409 auto query = R"(query getName { dog { name @@ -110,9 +110,9 @@ TEST_F(ValidationExamplesCase, CounterExample93) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample94) +TEST_F(ValidationExamplesCase, CounterExample105) { - // http://spec.graphql.org/June2018/#example-77c2e + // https://spec.graphql.org/October2021/#example-77c2e auto query = R"(query dogOperation { dog { name @@ -135,9 +135,9 @@ TEST_F(ValidationExamplesCase, CounterExample94) << "error should match"; } -TEST_F(ValidationExamplesCase, Example95) +TEST_F(ValidationExamplesCase, Example106) { - // http://spec.graphql.org/June2018/#example-be853 + // https://spec.graphql.org/October2021/#example-be853 auto query = R"({ dog { name @@ -149,9 +149,9 @@ TEST_F(ValidationExamplesCase, Example95) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample96) +TEST_F(ValidationExamplesCase, CounterExample107) { - // http://spec.graphql.org/June2018/#example-44b85 + // https://spec.graphql.org/October2021/#example-44b85 auto query = R"({ dog { name @@ -176,9 +176,9 @@ TEST_F(ValidationExamplesCase, CounterExample96) << "error should match"; } -TEST_F(ValidationExamplesCase, Example97) +TEST_F(ValidationExamplesCase, Example108) { - // http://spec.graphql.org/June2018/#example-5bbc3 + // https://spec.graphql.org/October2021/#example-5bbc3 auto query = R"(subscription sub { newMessage { body @@ -191,9 +191,9 @@ TEST_F(ValidationExamplesCase, Example97) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, Example98) +TEST_F(ValidationExamplesCase, Example109) { - // http://spec.graphql.org/June2018/#example-13061 + // https://spec.graphql.org/October2021/#example-13061 auto query = R"(subscription sub { ...newMessageFields } @@ -210,9 +210,9 @@ TEST_F(ValidationExamplesCase, Example98) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample99) +TEST_F(ValidationExamplesCase, CounterExample110) { - // http://spec.graphql.org/June2018/#example-3997d + // https://spec.graphql.org/October2021/#example-3997d auto query = R"(subscription sub { newMessage { body @@ -231,9 +231,9 @@ TEST_F(ValidationExamplesCase, CounterExample99) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample100) +TEST_F(ValidationExamplesCase, CounterExample111) { - // http://spec.graphql.org/June2018/#example-18466 + // https://spec.graphql.org/October2021/#example-18466 auto query = R"(subscription sub { ...multipleSubscriptions } @@ -256,14 +256,10 @@ TEST_F(ValidationExamplesCase, CounterExample100) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample101) +TEST_F(ValidationExamplesCase, CounterExample112) { - // http://spec.graphql.org/June2018/#example-2353b + // https://spec.graphql.org/October2021/#example-a8fa1 auto query = R"(subscription sub { - newMessage { - body - sender - } __typename })"_graphql; @@ -272,14 +268,14 @@ TEST_F(ValidationExamplesCase, CounterExample101) ASSERT_EQ(errors.size(), 1); EXPECT_EQ( - R"js({"message":"Subscription with more than one root field name: sub","locations":[{"line":1,"column":1}]})js", + R"js({"message":"Subscription with Introspection root field name: sub","locations":[{"line":1,"column":1}]})js", response::toJSON(std::move(errors[0]))) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample102) +TEST_F(ValidationExamplesCase, CounterExample113) { - // http://spec.graphql.org/June2018/#example-48706 + // https://spec.graphql.org/October2021/#example-48706 auto query = R"(fragment fieldNotDefined on Dog { meowVolume } @@ -303,9 +299,9 @@ TEST_F(ValidationExamplesCase, CounterExample102) << "error should match"; } -TEST_F(ValidationExamplesCase, Example103) +TEST_F(ValidationExamplesCase, Example114) { - // http://spec.graphql.org/June2018/#example-d34e0 + // https://spec.graphql.org/October2021/#example-d34e0 auto query = R"(fragment interfaceFieldSelection on Pet { name } @@ -321,9 +317,9 @@ TEST_F(ValidationExamplesCase, Example103) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample104) +TEST_F(ValidationExamplesCase, CounterExample115) { - // http://spec.graphql.org/June2018/#example-db33b + // https://spec.graphql.org/October2021/#example-db33b auto query = R"(fragment definedOnImplementorsButNotInterface on Pet { nickname })"_graphql; @@ -339,9 +335,9 @@ TEST_F(ValidationExamplesCase, CounterExample104) << "error should match"; } -TEST_F(ValidationExamplesCase, Example105) +TEST_F(ValidationExamplesCase, Example116) { - // http://spec.graphql.org/June2018/#example-245fa + // https://spec.graphql.org/October2021/#example-245fa auto query = R"(fragment inDirectFieldSelectionOnUnion on CatOrDog { __typename ... on Pet { @@ -363,9 +359,9 @@ TEST_F(ValidationExamplesCase, Example105) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample106) +TEST_F(ValidationExamplesCase, CounterExample117) { - // http://spec.graphql.org/June2018/#example-252ad + // https://spec.graphql.org/October2021/#example-252ad auto query = R"(fragment directFieldSelectionOnUnion on CatOrDog { name barkVolume @@ -386,9 +382,9 @@ TEST_F(ValidationExamplesCase, CounterExample106) << "error should match"; } -TEST_F(ValidationExamplesCase, Example107) +TEST_F(ValidationExamplesCase, Example118) { - // http://spec.graphql.org/June2018/#example-4e10c + // https://spec.graphql.org/October2021/#example-4e10c auto query = R"(fragment mergeIdenticalFields on Dog { name name @@ -411,9 +407,9 @@ TEST_F(ValidationExamplesCase, Example107) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample108) +TEST_F(ValidationExamplesCase, CounterExample119) { - // http://spec.graphql.org/June2018/#example-a2230 + // https://spec.graphql.org/October2021/#example-a2230 auto query = R"(fragment conflictingBecauseAlias on Dog { name: nickname name @@ -430,9 +426,9 @@ TEST_F(ValidationExamplesCase, CounterExample108) << "error should match"; } -TEST_F(ValidationExamplesCase, Example109) +TEST_F(ValidationExamplesCase, Example120) { - // http://spec.graphql.org/June2018/#example-b6369 + // https://spec.graphql.org/October2021/#example-b6369 auto query = R"(fragment mergeIdenticalFieldsWithIdenticalArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: SIT) @@ -460,9 +456,9 @@ TEST_F(ValidationExamplesCase, Example109) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample110) +TEST_F(ValidationExamplesCase, CounterExample121) { - // http://spec.graphql.org/June2018/#example-00fbf + // https://spec.graphql.org/October2021/#example-00fbf auto query = R"(fragment conflictingArgsOnValues on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: HEEL) @@ -506,9 +502,9 @@ TEST_F(ValidationExamplesCase, CounterExample110) << "error should match"; } -TEST_F(ValidationExamplesCase, Example111) +TEST_F(ValidationExamplesCase, Example122) { - // http://spec.graphql.org/June2018/#example-a8406 + // https://spec.graphql.org/October2021/#example-a8406 auto query = R"(fragment safeDifferingFields on Pet { ... on Dog { volume: barkVolume @@ -539,9 +535,9 @@ TEST_F(ValidationExamplesCase, Example111) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample112) +TEST_F(ValidationExamplesCase, CounterExample123) { - // http://spec.graphql.org/June2018/#example-54e3d + // https://spec.graphql.org/October2021/#example-54e3d auto query = R"(fragment conflictingDifferingResponses on Pet { ... on Dog { someValue: nickname @@ -562,9 +558,9 @@ TEST_F(ValidationExamplesCase, CounterExample112) << "error should match"; } -TEST_F(ValidationExamplesCase, Example113) +TEST_F(ValidationExamplesCase, Example124) { - // http://spec.graphql.org/June2018/#example-e23c5 + // https://spec.graphql.org/October2021/#example-e23c5 auto query = R"(fragment scalarSelection on Dog { barkVolume } @@ -580,9 +576,9 @@ TEST_F(ValidationExamplesCase, Example113) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample114) +TEST_F(ValidationExamplesCase, CounterExample125) { - // http://spec.graphql.org/June2018/#example-13b69 + // https://spec.graphql.org/October2021/#example-13b69 auto query = R"(fragment scalarSelectionsNotAllowedOnInt on Dog { barkVolume { sinceWhen @@ -600,9 +596,9 @@ TEST_F(ValidationExamplesCase, CounterExample114) << "error should match"; } -TEST_F(ValidationExamplesCase, Example115) +TEST_F(ValidationExamplesCase, Example126) { - // http://spec.graphql.org/June2018/#example-9bada + // https://spec.graphql.org/October2021/#example-9bada auto query = R"(query { human { name @@ -625,9 +621,9 @@ TEST_F(ValidationExamplesCase, Example115) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample116) +TEST_F(ValidationExamplesCase, CounterExample127) { - // http://spec.graphql.org/June2018/#example-d68ee + // https://spec.graphql.org/October2021/#example-d68ee auto query = R"(query directQueryOnObjectWithoutSubFields { human } @@ -658,9 +654,9 @@ TEST_F(ValidationExamplesCase, CounterExample116) << "error should match"; } -TEST_F(ValidationExamplesCase, Example117) +TEST_F(ValidationExamplesCase, Example128) { - // http://spec.graphql.org/June2018/#example-760cb + // https://spec.graphql.org/October2021/#example-dfd15 auto query = R"(fragment argOnRequiredArg on Dog { doesKnowCommand(dogCommand: SIT) } @@ -681,9 +677,9 @@ TEST_F(ValidationExamplesCase, Example117) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample118) +TEST_F(ValidationExamplesCase, CounterExample129) { - // http://spec.graphql.org/June2018/#example-d5639 + // https://spec.graphql.org/October2021/#example-d5639 auto query = R"(fragment invalidArgName on Dog { doesKnowCommand(command: CLEAN_UP_HOUSE) })"_graphql; @@ -699,9 +695,9 @@ TEST_F(ValidationExamplesCase, CounterExample118) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample119) +TEST_F(ValidationExamplesCase, CounterExample130) { - // http://spec.graphql.org/June2018/#example-4feee + // https://spec.graphql.org/October2021/#example-df41e auto query = R"(fragment invalidArgName on Dog { isHousetrained(atOtherHomes: true) @include(unless: false) })"_graphql; @@ -717,9 +713,9 @@ TEST_F(ValidationExamplesCase, CounterExample119) << "error should match"; } -TEST_F(ValidationExamplesCase, Example120) +TEST_F(ValidationExamplesCase, Example131) { - // http://spec.graphql.org/June2018/#example-1891c + // https://spec.graphql.org/October2021/#example-73706 auto query = R"(query { arguments { multipleReqs(x: 1, y: 2) @@ -731,9 +727,9 @@ TEST_F(ValidationExamplesCase, Example120) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, Example121) +TEST_F(ValidationExamplesCase, Example132) { - // http://spec.graphql.org/June2018/#example-18fab + // https://spec.graphql.org/October2021/#example-bda7e auto query = R"(fragment multipleArgs on Arguments { multipleReqs(x: 1, y: 2) } @@ -759,9 +755,9 @@ TEST_F(ValidationExamplesCase, Example121) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, Example122) +TEST_F(ValidationExamplesCase, Example133) { - // http://spec.graphql.org/June2018/#example-503bd + // https://spec.graphql.org/October2021/#example-503bd auto query = R"(fragment goodBooleanArg on Arguments { booleanArgField(booleanArg: true) } @@ -782,9 +778,9 @@ TEST_F(ValidationExamplesCase, Example122) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, Example123) +TEST_F(ValidationExamplesCase, Example134) { - // http://spec.graphql.org/June2018/#example-1f1d2 + // https://spec.graphql.org/October2021/#example-1f1d2 auto query = R"(fragment goodBooleanArgDefault on Arguments { booleanArgField } @@ -800,9 +796,9 @@ TEST_F(ValidationExamplesCase, Example123) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample124) +TEST_F(ValidationExamplesCase, CounterExample135) { - // http://spec.graphql.org/June2018/#example-f12a1 + // https://spec.graphql.org/October2021/#example-f12a1 auto query = R"(fragment missingRequiredArg on Arguments { nonNullBooleanArgField })"_graphql; @@ -818,9 +814,9 @@ TEST_F(ValidationExamplesCase, CounterExample124) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample125) +TEST_F(ValidationExamplesCase, CounterExample136) { - // http://spec.graphql.org/June2018/#example-0bc81 + // https://spec.graphql.org/October2021/#example-0bc81 auto query = R"(fragment missingRequiredArg on Arguments { nonNullBooleanArgField(nonNullBooleanArg: null) })"_graphql; @@ -836,9 +832,9 @@ TEST_F(ValidationExamplesCase, CounterExample125) << "error should match"; } -TEST_F(ValidationExamplesCase, Example126) +TEST_F(ValidationExamplesCase, Example137) { - // http://spec.graphql.org/June2018/#example-3703b + // https://spec.graphql.org/October2021/#example-3703b auto query = R"({ dog { ...fragmentOne @@ -861,9 +857,9 @@ TEST_F(ValidationExamplesCase, Example126) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample127) +TEST_F(ValidationExamplesCase, CounterExample138) { - // http://spec.graphql.org/June2018/#example-2c3e3 + // https://spec.graphql.org/October2021/#example-2c3e3 auto query = R"({ dog { ...fragmentOne @@ -891,9 +887,9 @@ TEST_F(ValidationExamplesCase, CounterExample127) << "error should match"; } -TEST_F(ValidationExamplesCase, Example128) +TEST_F(ValidationExamplesCase, Example139) { - // http://spec.graphql.org/June2018/#example-1b2da + // https://spec.graphql.org/October2021/#example-1b2da auto query = R"(fragment correctType on Dog { name } @@ -923,9 +919,9 @@ TEST_F(ValidationExamplesCase, Example128) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample129) +TEST_F(ValidationExamplesCase, CounterExample140) { - // http://spec.graphql.org/June2018/#example-463f6 + // https://spec.graphql.org/October2021/#example-463f6 auto query = R"(fragment notOnExistingType on NotInSchema { name } @@ -951,9 +947,9 @@ TEST_F(ValidationExamplesCase, CounterExample129) << "error should match"; } -TEST_F(ValidationExamplesCase, Example130) +TEST_F(ValidationExamplesCase, Example141) { - // http://spec.graphql.org/June2018/#example-3c8d4 + // https://spec.graphql.org/October2021/#example-3c8d4 auto query = R"(fragment fragOnObject on Dog { name } @@ -981,9 +977,9 @@ TEST_F(ValidationExamplesCase, Example130) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample131) +TEST_F(ValidationExamplesCase, CounterExample142) { - // http://spec.graphql.org/June2018/#example-4d5e5 + // https://spec.graphql.org/October2021/#example-4d5e5 auto query = R"(fragment fragOnScalar on Int { something } @@ -1009,9 +1005,9 @@ TEST_F(ValidationExamplesCase, CounterExample131) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample132) +TEST_F(ValidationExamplesCase, CounterExample143) { - // http://spec.graphql.org/June2018/#example-9e1e3 + // https://spec.graphql.org/October2021/#example-9e1e3 auto query = R"(fragment nameFragment on Dog { # unused name } @@ -1033,9 +1029,9 @@ TEST_F(ValidationExamplesCase, CounterExample132) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample133) +TEST_F(ValidationExamplesCase, CounterExample144) { - // http://spec.graphql.org/June2018/#example-28421 + // https://spec.graphql.org/October2021/#example-28421 auto query = R"({ dog { ...undefinedFragment @@ -1053,9 +1049,9 @@ TEST_F(ValidationExamplesCase, CounterExample133) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample134) +TEST_F(ValidationExamplesCase, CounterExample145) { - // http://spec.graphql.org/June2018/#example-9ceb4 + // https://spec.graphql.org/October2021/#example-9ceb4 auto query = R"({ dog { ...nameFragment @@ -1087,9 +1083,9 @@ TEST_F(ValidationExamplesCase, CounterExample134) << "error should match"; } -TEST_F(ValidationExamplesCase, Example135) +TEST_F(ValidationExamplesCase, Example146) { - // http://spec.graphql.org/June2018/#example-08734 + // https://spec.graphql.org/October2021/#example-08734 auto query = R"({ dog { name @@ -1108,9 +1104,9 @@ TEST_F(ValidationExamplesCase, Example135) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample136) +TEST_F(ValidationExamplesCase, CounterExample147) { - // http://spec.graphql.org/June2018/#example-6bbad + // https://spec.graphql.org/October2021/#example-cd11c auto query = R"({ dog { ...dogFragment @@ -1148,9 +1144,9 @@ TEST_F(ValidationExamplesCase, CounterExample136) << "error should match"; } -TEST_F(ValidationExamplesCase, Example137) +TEST_F(ValidationExamplesCase, Example148) { - // http://spec.graphql.org/June2018/#example-0fc38 + // https://spec.graphql.org/October2021/#example-0fc38 auto query = R"(fragment dogFragment on Dog { ... on Dog { barkVolume @@ -1168,9 +1164,9 @@ TEST_F(ValidationExamplesCase, Example137) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample138) +TEST_F(ValidationExamplesCase, CounterExample149) { - // http://spec.graphql.org/June2018/#example-4d411 + // https://spec.graphql.org/October2021/#example-4d411 auto query = R"(fragment catInDogFragmentInvalid on Dog { ... on Cat { meowVolume @@ -1188,9 +1184,9 @@ TEST_F(ValidationExamplesCase, CounterExample138) << "error should match"; } -TEST_F(ValidationExamplesCase, Example139) +TEST_F(ValidationExamplesCase, Example150) { - // http://spec.graphql.org/June2018/#example-2c8d0 + // https://spec.graphql.org/October2021/#example-2c8d0 auto query = R"(fragment petNameFragment on Pet { name } @@ -1210,9 +1206,9 @@ TEST_F(ValidationExamplesCase, Example139) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, Example140) +TEST_F(ValidationExamplesCase, Example151) { - // http://spec.graphql.org/June2018/#example-41843 + // https://spec.graphql.org/October2021/#example-41843 auto query = R"(fragment catOrDogNameFragment on CatOrDog { ... on Cat { meowVolume @@ -1234,9 +1230,9 @@ TEST_F(ValidationExamplesCase, Example140) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, Example141) +TEST_F(ValidationExamplesCase, Example152) { - // http://spec.graphql.org/June2018/#example-85110 + // https://spec.graphql.org/October2021/#example-85110 auto query = R"(fragment petFragment on Pet { name ... on Dog { @@ -1262,9 +1258,9 @@ TEST_F(ValidationExamplesCase, Example141) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample142) +TEST_F(ValidationExamplesCase, CounterExample153) { - // http://spec.graphql.org/June2018/#example-a8dcc + // https://spec.graphql.org/October2021/#example-a8dcc auto query = R"(fragment sentientFragment on Sentient { ... on Dog { barkVolume @@ -1292,9 +1288,9 @@ TEST_F(ValidationExamplesCase, CounterExample142) << "error should match"; } -TEST_F(ValidationExamplesCase, Example143) +TEST_F(ValidationExamplesCase, Example154) { - // http://spec.graphql.org/June2018/#example-dc875 + // https://spec.graphql.org/October2021/#example-dc875 auto query = R"(fragment unionWithInterface on Pet { ...dogOrHumanFragment } @@ -1316,9 +1312,9 @@ TEST_F(ValidationExamplesCase, Example143) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample144) +TEST_F(ValidationExamplesCase, CounterExample155) { - // http://spec.graphql.org/June2018/#example-c9c63 + // https://spec.graphql.org/October2021/#example-c9c63 auto query = R"(fragment nonIntersectingInterfaces on Pet { ...sentientFragment } @@ -1338,9 +1334,31 @@ TEST_F(ValidationExamplesCase, CounterExample144) << "error should match"; } -TEST_F(ValidationExamplesCase, Example145) +TEST_F(ValidationExamplesCase, Example156) +{ + // https://spec.graphql.org/October2021/#example-bc12a + auto query = R"(fragment interfaceWithInterface on Node { + ...resourceFragment + } + + fragment resourceFragment on Resource { + url + } + + query { + resource { + ...interfaceWithInterface + } + })"_graphql; + + auto errors = _service->validate(query); + + ASSERT_TRUE(errors.empty()); +} + +TEST_F(ValidationExamplesCase, Example157) { - // http://spec.graphql.org/June2018/#example-7ee0e + // https://spec.graphql.org/October2021/#example-7ee0e auto query = R"(fragment goodBooleanArg on Arguments { booleanArgField(booleanArg: true) } @@ -1366,9 +1384,9 @@ TEST_F(ValidationExamplesCase, Example145) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample146) +TEST_F(ValidationExamplesCase, CounterExample158) { - // http://spec.graphql.org/June2018/#example-3a7c1 + // https://spec.graphql.org/October2021/#example-3a7c1 auto query = R"(fragment stringIntoInt on Arguments { intArgField(intArg: "123") } @@ -1401,9 +1419,9 @@ TEST_F(ValidationExamplesCase, CounterExample146) << "error should match"; } -TEST_F(ValidationExamplesCase, Example147) +TEST_F(ValidationExamplesCase, Example159) { - // http://spec.graphql.org/June2018/#example-a940b + // https://spec.graphql.org/October2021/#example-a940b auto query = R"({ findDog(complex: { name: "Fido" }) { name @@ -1415,9 +1433,9 @@ TEST_F(ValidationExamplesCase, Example147) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample148) +TEST_F(ValidationExamplesCase, CounterExample160) { - // http://spec.graphql.org/June2018/#example-1a5f6 + // https://spec.graphql.org/October2021/#example-1a5f6 auto query = R"({ findDog(complex: { favoriteCookieFlavor: "Bacon" }) { name @@ -1439,9 +1457,9 @@ TEST_F(ValidationExamplesCase, CounterExample148) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample149) +TEST_F(ValidationExamplesCase, CounterExample161) { - // http://spec.graphql.org/June2018/#example-5d541 + // https://spec.graphql.org/October2021/#example-5d541 auto query = R"({ findDog(complex: { name: "Fido", name: "Fido" }) { name @@ -1459,9 +1477,9 @@ TEST_F(ValidationExamplesCase, CounterExample149) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample150) +TEST_F(ValidationExamplesCase, CounterExample162) { - // http://spec.graphql.org/June2018/#example-55f3f + // https://spec.graphql.org/October2021/#example-55f3f auto query = R"(query @skip(if: $foo) { dog { name @@ -1479,9 +1497,9 @@ TEST_F(ValidationExamplesCase, CounterExample150) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample151) +TEST_F(ValidationExamplesCase, CounterExample163) { - // http://spec.graphql.org/June2018/#example-b2e6c + // https://spec.graphql.org/October2021/#example-b2e6c auto query = R"(query ($foo: Boolean = true, $bar: Boolean = false) { dog @skip(if: $foo) @skip(if: $bar) { name @@ -1499,9 +1517,9 @@ TEST_F(ValidationExamplesCase, CounterExample151) << "error should match"; } -TEST_F(ValidationExamplesCase, Example152) +TEST_F(ValidationExamplesCase, Example164) { - // http://spec.graphql.org/June2018/#example-c5ee9 + // https://spec.graphql.org/October2021/#example-c5ee9 auto query = R"(query ($foo: Boolean = true, $bar: Boolean = false) { dog @skip(if: $foo) { name @@ -1516,9 +1534,9 @@ TEST_F(ValidationExamplesCase, Example152) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample153) +TEST_F(ValidationExamplesCase, CounterExample165) { - // http://spec.graphql.org/June2018/#example-b767a + // https://spec.graphql.org/October2021/#example-abc9c auto query = R"(query houseTrainedQuery($atOtherHomes: Boolean, $atOtherHomes: Boolean) { dog { isHousetrained(atOtherHomes: $atOtherHomes) @@ -1536,9 +1554,9 @@ TEST_F(ValidationExamplesCase, CounterExample153) << "error should match"; } -TEST_F(ValidationExamplesCase, Example154) +TEST_F(ValidationExamplesCase, Example166) { - // http://spec.graphql.org/June2018/#example-6f6b9 + // https://spec.graphql.org/October2021/#example-54c93 auto query = R"(query A($atOtherHomes: Boolean) { ...HouseTrainedFragment } @@ -1558,9 +1576,9 @@ TEST_F(ValidationExamplesCase, Example154) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, Example155) +TEST_F(ValidationExamplesCase, Example167) { - // http://spec.graphql.org/June2018/#example-f3185 + // https://spec.graphql.org/October2021/#example-ce150 auto query = R"(query takesComplexInput($complexInput: ComplexInput) { findDog(complex: $complexInput) { name @@ -1572,9 +1590,9 @@ TEST_F(ValidationExamplesCase, Example155) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, Example156) +TEST_F(ValidationExamplesCase, Example168) { - // http://spec.graphql.org/June2018/#example-77f18 + // https://spec.graphql.org/October2021/#example-a4255 auto query = R"(query takesBoolean($atOtherHomes: Boolean) { dog { isHousetrained(atOtherHomes: $atOtherHomes) @@ -1596,9 +1614,9 @@ TEST_F(ValidationExamplesCase, Example156) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample157) +TEST_F(ValidationExamplesCase, CounterExample169) { - // http://spec.graphql.org/June2018/#example-aeba9 + // https://spec.graphql.org/October2021/#example-aeba9 auto query = R"(query takesCat($cat: Cat) { dog { name @@ -1646,9 +1664,9 @@ TEST_F(ValidationExamplesCase, CounterExample157) << "error should match"; } -TEST_F(ValidationExamplesCase, Example158) +TEST_F(ValidationExamplesCase, Example170) { - // http://spec.graphql.org/June2018/#example-a5099 + // https://spec.graphql.org/October2021/#example-38119 auto query = R"(query variableIsDefined($atOtherHomes: Boolean) { dog { isHousetrained(atOtherHomes: $atOtherHomes) @@ -1660,9 +1678,9 @@ TEST_F(ValidationExamplesCase, Example158) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample159) +TEST_F(ValidationExamplesCase, CounterExample171) { - // http://spec.graphql.org/June2018/#example-c8425 + // https://spec.graphql.org/October2021/#example-5ba94 auto query = R"(query variableIsNotDefined { dog { isHousetrained(atOtherHomes: $atOtherHomes) @@ -1680,9 +1698,9 @@ TEST_F(ValidationExamplesCase, CounterExample159) << "error should match"; } -TEST_F(ValidationExamplesCase, Example160) +TEST_F(ValidationExamplesCase, Example172) { - // http://spec.graphql.org/June2018/#example-f4a77 + // https://spec.graphql.org/October2021/#example-559c2 auto query = R"(query variableIsDefinedUsedInSingleFragment($atOtherHomes: Boolean) { dog { ...isHousetrainedFragment @@ -1698,9 +1716,9 @@ TEST_F(ValidationExamplesCase, Example160) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample161) +TEST_F(ValidationExamplesCase, CounterExample173) { - // http://spec.graphql.org/June2018/#example-8c8db + // https://spec.graphql.org/October2021/#example-93d3e auto query = R"(query variableIsNotDefinedUsedInSingleFragment { dog { ...isHousetrainedFragment @@ -1722,9 +1740,9 @@ TEST_F(ValidationExamplesCase, CounterExample161) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample162) +TEST_F(ValidationExamplesCase, CounterExample174) { - // http://spec.graphql.org/June2018/#example-7b65c + // https://spec.graphql.org/October2021/#example-ee7be auto query = R"(query variableIsNotDefinedUsedInNestedFragment { dog { ...outerHousetrainedFragment @@ -1750,9 +1768,9 @@ TEST_F(ValidationExamplesCase, CounterExample162) << "error should match"; } -TEST_F(ValidationExamplesCase, Example163) +TEST_F(ValidationExamplesCase, Example175) { - // http://spec.graphql.org/June2018/#example-84129 + // https://spec.graphql.org/October2021/#example-d601e auto query = R"(query housetrainedQueryOne($atOtherHomes: Boolean) { dog { ...isHousetrainedFragment @@ -1774,9 +1792,9 @@ TEST_F(ValidationExamplesCase, Example163) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample164) +TEST_F(ValidationExamplesCase, CounterExample176) { - // http://spec.graphql.org/June2018/#example-ef68a + // https://spec.graphql.org/October2021/#example-2b284 auto query = R"(query housetrainedQueryOne($atOtherHomes: Boolean) { dog { ...isHousetrainedFragment @@ -1804,9 +1822,9 @@ TEST_F(ValidationExamplesCase, CounterExample164) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample165) +TEST_F(ValidationExamplesCase, CounterExample177) { - // http://spec.graphql.org/June2018/#example-516af + // https://spec.graphql.org/October2021/#example-464b6 auto query = R"(query variableUnused($atOtherHomes: Boolean) { dog { isHousetrained @@ -1824,9 +1842,9 @@ TEST_F(ValidationExamplesCase, CounterExample165) << "error should match"; } -TEST_F(ValidationExamplesCase, Example166) +TEST_F(ValidationExamplesCase, Example178) { - // http://spec.graphql.org/June2018/#example-ed1fa + // https://spec.graphql.org/October2021/#example-6d4bb auto query = R"(query variableUsedInFragment($atOtherHomes: Boolean) { dog { ...isHousetrainedFragment @@ -1842,9 +1860,9 @@ TEST_F(ValidationExamplesCase, Example166) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample167) +TEST_F(ValidationExamplesCase, CounterExample179) { - // http://spec.graphql.org/June2018/#example-f6c72 + // https://spec.graphql.org/October2021/#example-a30e2 auto query = R"(query variableNotUsedWithinFragment($atOtherHomes: Boolean) { dog { ...isHousetrainedWithoutVariableFragment @@ -1866,9 +1884,9 @@ TEST_F(ValidationExamplesCase, CounterExample167) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample168) +TEST_F(ValidationExamplesCase, CounterExample180) { - // http://spec.graphql.org/June2018/#example-5593f + // https://spec.graphql.org/October2021/#example-e647f auto query = R"(query queryWithUsedVar($atOtherHomes: Boolean) { dog { ...isHousetrainedFragment @@ -1896,9 +1914,9 @@ TEST_F(ValidationExamplesCase, CounterExample168) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample169) +TEST_F(ValidationExamplesCase, CounterExample181) { - // http://spec.graphql.org/June2018/#example-2028e + // https://spec.graphql.org/October2021/#example-2028e auto query = R"(query intCannotGoIntoBoolean($intArg: Int) { arguments { booleanArgField(booleanArg: $intArg) @@ -1916,9 +1934,9 @@ TEST_F(ValidationExamplesCase, CounterExample169) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample170) +TEST_F(ValidationExamplesCase, CounterExample182) { - // http://spec.graphql.org/June2018/#example-8d369 + // https://spec.graphql.org/October2021/#example-8d369 auto query = R"(query booleanListCannotGoIntoBoolean($booleanListArg: [Boolean]) { arguments { booleanArgField(booleanArg: $booleanListArg) @@ -1936,9 +1954,9 @@ TEST_F(ValidationExamplesCase, CounterExample170) << "error should match"; } -TEST_F(ValidationExamplesCase, CounterExample171) +TEST_F(ValidationExamplesCase, CounterExample183) { - // http://spec.graphql.org/June2018/#example-ed727 + // https://spec.graphql.org/October2021/#example-ed727 auto query = R"(query booleanArgQuery($booleanArg: Boolean) { arguments { nonNullBooleanArgField(nonNullBooleanArg: $booleanArg) @@ -1956,9 +1974,9 @@ TEST_F(ValidationExamplesCase, CounterExample171) << "error should match"; } -TEST_F(ValidationExamplesCase, Example172) +TEST_F(ValidationExamplesCase, Example184) { - // http://spec.graphql.org/June2018/#example-c5959 + // https://spec.graphql.org/October2021/#example-c5959 auto query = R"(query nonNullListToList($nonNullBooleanList: [Boolean]!) { arguments { booleanListArgField(booleanListArg: $nonNullBooleanList) @@ -1970,9 +1988,9 @@ TEST_F(ValidationExamplesCase, Example172) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, CounterExample173) +TEST_F(ValidationExamplesCase, CounterExample185) { - // http://spec.graphql.org/June2018/#example-64255 + // https://spec.graphql.org/October2021/#example-64255 auto query = R"(query listToNonNullList($booleanList: [Boolean]) { arguments { nonNullBooleanListField(nonNullBooleanListArg: $booleanList) @@ -1990,9 +2008,9 @@ TEST_F(ValidationExamplesCase, CounterExample173) << "error should match"; } -TEST_F(ValidationExamplesCase, Example174) +TEST_F(ValidationExamplesCase, Example186) { - // http://spec.graphql.org/June2018/#example-0877c + // https://spec.graphql.org/October2021/#example-0877c auto query = R"(query booleanArgQueryWithDefault($booleanArg: Boolean) { arguments { optionalNonNullBooleanArgField(optionalBooleanArg: $booleanArg) @@ -2004,9 +2022,9 @@ TEST_F(ValidationExamplesCase, Example174) ASSERT_TRUE(errors.empty()); } -TEST_F(ValidationExamplesCase, Example175) +TEST_F(ValidationExamplesCase, Example187) { - // http://spec.graphql.org/June2018/#example-d24d9 + // https://spec.graphql.org/October2021/#example-d24d9 auto query = R"(query booleanArgQueryWithDefault($booleanArg: Boolean = true) { arguments { nonNullBooleanArgField(nonNullBooleanArg: $booleanArg)