From d3c7aa34f83d95d8ccc9ee3f6b01a67646f0dcd8 Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Wed, 7 Oct 2020 12:05:17 -0500 Subject: [PATCH 01/16] Upgrade gradle and use latest common build scripts --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 55741 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 53 ++++++++++++++--------- gradlew.bat | 43 ++++++++++-------- 5 files changed, 59 insertions(+), 42 deletions(-) diff --git a/build.gradle b/build.gradle index 49fa417b..42462654 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ repositories { version project.projectVersion ext { - commonBuild = 'https://raw.githubusercontent.com/grails/grails-common-build/47f0f2e0d9d82030b758c6dfe7bc7eefe6582342' + commonBuild = 'https://raw.githubusercontent.com/grails/grails-common-build/9531dd5e6d774b86e2d8220aff3bcec3add43320' } subprojects { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 457aad0d98108420a977756b7145c93c8910b076..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 GIT binary patch delta 32671 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 delta 29482 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 Xl$U}8nGXl$9Q3CH>hr|=o}d07!s7Wl diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 833d3072..12d38de6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Wed Dec 05 20:00:27 CET 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-all.zip diff --git a/gradlew b/gradlew index af6708ff..4f906e0c 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m"' +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -66,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -109,10 +126,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -138,19 +156,19 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -159,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 0f8d5937..ac1b06f9 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell From 3192f53d905c947737cee7d6d9b613c5fa5889fb Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Wed, 7 Oct 2020 12:05:42 -0500 Subject: [PATCH 02/16] build-scan plugin no longer works w/ gradle 6+ --- build.gradle | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 42462654..ab9cea3a 100644 --- a/build.gradle +++ b/build.gradle @@ -11,9 +11,9 @@ buildscript { } } -plugins { - id 'com.gradle.build-scan' version '2.0.2' -} +//plugins { +// id 'com.gradle.build-scan' version '2.0.2' +//} repositories { maven { url "https://repo.grails.org/grails/core" } @@ -93,7 +93,7 @@ subprojects { } } -buildScan { - termsOfServiceUrl = 'https://gradle.com/terms-of-service' - termsOfServiceAgree = 'yes' -} +//buildScan { +// termsOfServiceUrl = 'https://gradle.com/terms-of-service' +// termsOfServiceAgree = 'yes' +//} From a839af6e60e2bdec5a51c6c1dad6663df2d89b77 Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Wed, 7 Oct 2020 12:09:44 -0500 Subject: [PATCH 03/16] Promote for reuse by fields --- .../{operations => }/arguments/ComplexArgument.groovy | 2 +- .../entity/{operations => }/arguments/CustomArgument.groovy | 2 +- .../entity/{operations => }/arguments/SimpleArgument.groovy | 2 +- .../gorm/graphql/entity/operations/CustomOperation.groovy | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) rename core/src/main/groovy/org/grails/gorm/graphql/entity/{operations => }/arguments/ComplexArgument.groovy (96%) rename core/src/main/groovy/org/grails/gorm/graphql/entity/{operations => }/arguments/CustomArgument.groovy (95%) rename core/src/main/groovy/org/grails/gorm/graphql/entity/{operations => }/arguments/SimpleArgument.groovy (95%) diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/arguments/ComplexArgument.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/arguments/ComplexArgument.groovy similarity index 96% rename from core/src/main/groovy/org/grails/gorm/graphql/entity/operations/arguments/ComplexArgument.groovy rename to core/src/main/groovy/org/grails/gorm/graphql/entity/arguments/ComplexArgument.groovy index cba70951..7837b889 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/arguments/ComplexArgument.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/arguments/ComplexArgument.groovy @@ -1,4 +1,4 @@ -package org.grails.gorm.graphql.entity.operations.arguments +package org.grails.gorm.graphql.entity.arguments import graphql.schema.GraphQLInputType import groovy.transform.CompileStatic diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/arguments/CustomArgument.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/arguments/CustomArgument.groovy similarity index 95% rename from core/src/main/groovy/org/grails/gorm/graphql/entity/operations/arguments/CustomArgument.groovy rename to core/src/main/groovy/org/grails/gorm/graphql/entity/arguments/CustomArgument.groovy index de8d4bca..dd8f92db 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/arguments/CustomArgument.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/arguments/CustomArgument.groovy @@ -1,4 +1,4 @@ -package org.grails.gorm.graphql.entity.operations.arguments +package org.grails.gorm.graphql.entity.arguments import graphql.schema.GraphQLArgument import graphql.schema.GraphQLInputType diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/arguments/SimpleArgument.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/arguments/SimpleArgument.groovy similarity index 95% rename from core/src/main/groovy/org/grails/gorm/graphql/entity/operations/arguments/SimpleArgument.groovy rename to core/src/main/groovy/org/grails/gorm/graphql/entity/arguments/SimpleArgument.groovy index 7a9a28f4..27c3b2aa 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/arguments/SimpleArgument.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/arguments/SimpleArgument.groovy @@ -1,4 +1,4 @@ -package org.grails.gorm.graphql.entity.operations.arguments +package org.grails.gorm.graphql.entity.arguments import graphql.schema.GraphQLInputType import groovy.transform.CompileStatic diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy index d48b16a6..dec87a07 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy @@ -9,9 +9,9 @@ import org.grails.gorm.graphql.entity.dsl.helpers.Deprecatable import org.grails.gorm.graphql.entity.dsl.helpers.Describable import org.grails.gorm.graphql.entity.dsl.helpers.ExecutesClosures import org.grails.gorm.graphql.entity.dsl.helpers.Named -import org.grails.gorm.graphql.entity.operations.arguments.ComplexArgument -import org.grails.gorm.graphql.entity.operations.arguments.CustomArgument -import org.grails.gorm.graphql.entity.operations.arguments.SimpleArgument +import org.grails.gorm.graphql.entity.arguments.ComplexArgument +import org.grails.gorm.graphql.entity.arguments.CustomArgument +import org.grails.gorm.graphql.entity.arguments.SimpleArgument import org.grails.gorm.graphql.fetcher.interceptor.CustomMutationInterceptorInvoker import org.grails.gorm.graphql.fetcher.interceptor.CustomQueryInterceptorInvoker import org.grails.gorm.graphql.fetcher.interceptor.InterceptingDataFetcher From 5c2d39c791e18b92fe85be54a3e9bda81823df96 Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Fri, 9 Oct 2020 08:18:53 -0500 Subject: [PATCH 04/16] This has been resolved in groovy 2.5.6+ --- .../entity/dsl/helpers/ComplexTyped.groovy | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy index 3f9d573c..a0452c9a 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy @@ -25,7 +25,7 @@ import static graphql.schema.GraphQLInputObjectField.newInputObjectField * @since 1.0.0 */ @CompileStatic -trait ComplexTyped { +trait ComplexTyped extends ExecutesClosures { boolean collection = false @@ -43,24 +43,6 @@ trait ComplexTyped { (T)this } - /** - * This method exists because of https://issues.apache.org/jira/browse/GROOVY-8272 - * - * Normally this class could extend from {@link ExecutesClosures} - */ - private void withDelegate(Closure closure, Object delegate) { - if (closure != null) { - closure.resolveStrategy = Closure.DELEGATE_ONLY - closure.delegate = delegate - - try { - closure.call() - } finally { - closure.delegate = null - } - } - } - /** * Builds a custom object returnType if the supplied return returnType is a Map * From fc5d37ed0105ffcfd04c82264b3c8e562394f989 Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Fri, 9 Oct 2020 09:27:34 -0500 Subject: [PATCH 05/16] Explicitly upcast Appears to be some quirk with Traits perhaps, as this should implicitly upcast into an Object but it fails within this trait. This works everywhere else the ExecutesClosures trait is used. --- .../grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy index a0452c9a..cd0acdf3 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy @@ -113,7 +113,7 @@ trait ComplexTyped extends ExecutesClosures { private void handleField(Closure closure, Field field) { field.nullable(defaultNull) - withDelegate(closure, field) + withDelegate(closure, (Object)field) handleField(field) } From 28e175521912e9dd9391b0059d549a0dd54d6a2d Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Fri, 9 Oct 2020 09:29:24 -0500 Subject: [PATCH 06/16] Extract arguments into a trait Lets us be a bit more DRY as we reuse this --- .../entity/dsl/helpers/Arguable.groovy | 69 +++++++++++++++++++ .../entity/operations/CustomOperation.groovy | 54 +-------------- 2 files changed, 71 insertions(+), 52 deletions(-) create mode 100644 core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy new file mode 100644 index 00000000..7510ee2e --- /dev/null +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy @@ -0,0 +1,69 @@ +package org.grails.gorm.graphql.entity.dsl.helpers + +import groovy.transform.CompileStatic +import org.grails.gorm.graphql.entity.arguments.ComplexArgument +import org.grails.gorm.graphql.entity.arguments.CustomArgument +import org.grails.gorm.graphql.entity.arguments.SimpleArgument + +/** + * Decorates a class with a description property and builder method. + * + * @param The implementing class + * @author James Kleeh + * @since 1.0.0 + */ +@CompileStatic +trait Arguable extends ExecutesClosures { + + List arguments = [] + + private void handleArgumentClosure(CustomArgument argument, Closure closure) { + withDelegate(closure, (Object)argument) + argument.validate() + arguments.add(argument) + } + + /** + * Creates an argument to the operation that is a list of a simple type. + * The list can not have more than 1 element and that element must be a class. + * + * @param name The name of the argument + * @param type The returnType of the argument + * @param closure To provide additional data about the argument + * @return The operation in order to chain method calls + */ + T argument(String name, List type, @DelegatesTo(value = SimpleArgument, strategy = Closure.DELEGATE_ONLY) Closure closure = null) { + CustomArgument argument = new SimpleArgument().name(name).returns(type) + handleArgumentClosure(argument, closure) + (T)this + } + + /** + * Creates an argument to the operation that is of the returnType provided. + * + * @param name The name of the argument + * @param type The returnType of the argument + * @param closure To provide additional data about the argument + * @return The operation in order to chain method calls + */ + T argument(String name, Class type, @DelegatesTo(value = SimpleArgument, strategy = Closure.DELEGATE_ONLY) Closure closure = null) { + CustomArgument argument = new SimpleArgument().name(name).returns(type) + handleArgumentClosure(argument, closure) + (T)this + } + + /** + * Creates an argument to the operation that is a custom type. + * + * @param name The name of the argument + * @param closure To provide additional data about the argument + * @return The operation in order to chain method calls + */ + T argument(String name, String typeName, @DelegatesTo(value = ComplexArgument, strategy = Closure.DELEGATE_ONLY) Closure closure) { + CustomArgument argument = new ComplexArgument().name(name).typeName(typeName) + handleArgumentClosure(argument, closure) + (T)this + } + + +} \ No newline at end of file diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy index dec87a07..eb53d908 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy @@ -5,13 +5,12 @@ import groovy.transform.CompileStatic import org.grails.datastore.mapping.model.MappingContext import org.grails.datastore.mapping.model.PersistentEntity import org.grails.gorm.graphql.GraphQLServiceManager +import org.grails.gorm.graphql.entity.dsl.helpers.Arguable import org.grails.gorm.graphql.entity.dsl.helpers.Deprecatable import org.grails.gorm.graphql.entity.dsl.helpers.Describable import org.grails.gorm.graphql.entity.dsl.helpers.ExecutesClosures import org.grails.gorm.graphql.entity.dsl.helpers.Named -import org.grails.gorm.graphql.entity.arguments.ComplexArgument import org.grails.gorm.graphql.entity.arguments.CustomArgument -import org.grails.gorm.graphql.entity.arguments.SimpleArgument import org.grails.gorm.graphql.fetcher.interceptor.CustomMutationInterceptorInvoker import org.grails.gorm.graphql.fetcher.interceptor.CustomQueryInterceptorInvoker import org.grails.gorm.graphql.fetcher.interceptor.InterceptingDataFetcher @@ -29,9 +28,8 @@ import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition * @since 1.0.0 */ @CompileStatic -abstract class CustomOperation implements Named, Describable, Deprecatable, ExecutesClosures { +abstract class CustomOperation implements Named, Describable, Deprecatable, Arguable, ExecutesClosures { - private List arguments = [] private static InterceptorInvoker queryInvoker = new CustomQueryInterceptorInvoker() private static InterceptorInvoker mutationInvoker = new CustomMutationInterceptorInvoker() DataFetcher dataFetcher @@ -44,54 +42,6 @@ abstract class CustomOperation implements Named, Describable, Deprecata OperationType operationType - private void handleArgumentClosure(CustomArgument argument, Closure closure) { - withDelegate(closure, argument) - argument.validate() - arguments.add(argument) - } - - /** - * Creates an argument to the operation that is a list of a simple type. - * The list can not have more than 1 element and that element must be a class. - * - * @param name The name of the argument - * @param type The returnType of the argument - * @param closure To provide additional data about the argument - * @return The operation in order to chain method calls - */ - CustomOperation argument(String name, List type, @DelegatesTo(value = SimpleArgument, strategy = Closure.DELEGATE_ONLY) Closure closure = null) { - CustomArgument argument = new SimpleArgument().name(name).returns(type) - handleArgumentClosure(argument, closure) - this - } - - /** - * Creates an argument to the operation that is of the returnType provided. - * - * @param name The name of the argument - * @param type The returnType of the argument - * @param closure To provide additional data about the argument - * @return The operation in order to chain method calls - */ - CustomOperation argument(String name, Class type, @DelegatesTo(value = SimpleArgument, strategy = Closure.DELEGATE_ONLY) Closure closure = null) { - CustomArgument argument = new SimpleArgument().name(name).returns(type) - handleArgumentClosure(argument, closure) - this - } - - /** - * Creates an argument to the operation that is a custom type. - * - * @param name The name of the argument - * @param closure To provide additional data about the argument - * @return The operation in order to chain method calls - */ - CustomOperation argument(String name, String typeName, @DelegatesTo(value = ComplexArgument, strategy = Closure.DELEGATE_ONLY) Closure closure) { - CustomArgument argument = new ComplexArgument().name(name).typeName(typeName) - handleArgumentClosure(argument, closure) - this - } - /** * If the argument is true, the default list arguments created in the * schema through configuration will be prepended to any other From db1ff59763431f70538807479af311277b71e484 Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Mon, 9 Nov 2020 13:16:45 -0600 Subject: [PATCH 07/16] Fixes static compilation issue --- .../grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy index 7510ee2e..27dc29dd 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy @@ -32,7 +32,7 @@ trait Arguable extends ExecutesClosures { * @param closure To provide additional data about the argument * @return The operation in order to chain method calls */ - T argument(String name, List type, @DelegatesTo(value = SimpleArgument, strategy = Closure.DELEGATE_ONLY) Closure closure = null) { + T argument(String name, List> type, @DelegatesTo(value = SimpleArgument, strategy = Closure.DELEGATE_ONLY) Closure closure = null) { CustomArgument argument = new SimpleArgument().name(name).returns(type) handleArgumentClosure(argument, closure) (T)this @@ -46,7 +46,7 @@ trait Arguable extends ExecutesClosures { * @param closure To provide additional data about the argument * @return The operation in order to chain method calls */ - T argument(String name, Class type, @DelegatesTo(value = SimpleArgument, strategy = Closure.DELEGATE_ONLY) Closure closure = null) { + T argument(String name, Class type, @DelegatesTo(value = SimpleArgument, strategy = Closure.DELEGATE_ONLY) Closure closure = null) { CustomArgument argument = new SimpleArgument().name(name).returns(type) handleArgumentClosure(argument, closure) (T)this From 06d1392bb59b91f21edaf4e2b8ac753cda8d3872 Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Tue, 10 Nov 2020 07:38:38 -0600 Subject: [PATCH 08/16] Use arguments on properties With the exception of PersistentGraphQLProperties --- .../graphql/entity/property/impl/CustomGraphQLProperty.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/property/impl/CustomGraphQLProperty.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/property/impl/CustomGraphQLProperty.groovy index dfc17cbf..6420f5a2 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/property/impl/CustomGraphQLProperty.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/property/impl/CustomGraphQLProperty.groovy @@ -5,6 +5,7 @@ import graphql.schema.GraphQLType import groovy.transform.AutoClone import groovy.transform.CompileStatic import org.grails.datastore.mapping.model.MappingContext +import org.grails.gorm.graphql.entity.dsl.helpers.Arguable import org.grails.gorm.graphql.entity.dsl.helpers.Deprecatable import org.grails.gorm.graphql.entity.dsl.helpers.Describable import org.grails.gorm.graphql.entity.dsl.helpers.Named @@ -23,7 +24,7 @@ import org.grails.gorm.graphql.types.GraphQLTypeManager */ @AutoClone @CompileStatic -abstract class CustomGraphQLProperty extends OrderedGraphQLProperty implements Named, Describable, Deprecatable, Nullable { +abstract class CustomGraphQLProperty extends OrderedGraphQLProperty implements Named, Describable, Deprecatable, Nullable, Arguable { Integer order = null boolean input = true From b44c60cda7112312124e444a2300087c9fdab8e7 Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Tue, 10 Nov 2020 07:41:38 -0600 Subject: [PATCH 09/16] Support building field-level arguments --- .../gorm/graphql/entity/dsl/helpers/Arguable.groovy | 9 +++++++++ .../types/output/AbstractObjectTypeBuilder.groovy | 11 +++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy index 27dc29dd..940d34c2 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy @@ -1,9 +1,12 @@ package org.grails.gorm.graphql.entity.dsl.helpers +import graphql.schema.GraphQLArgument import groovy.transform.CompileStatic +import org.grails.datastore.mapping.model.MappingContext import org.grails.gorm.graphql.entity.arguments.ComplexArgument import org.grails.gorm.graphql.entity.arguments.CustomArgument import org.grails.gorm.graphql.entity.arguments.SimpleArgument +import org.grails.gorm.graphql.types.GraphQLTypeManager /** * Decorates a class with a description property and builder method. @@ -23,6 +26,12 @@ trait Arguable extends ExecutesClosures { arguments.add(argument) } + List getArguments(GraphQLTypeManager typeManager, MappingContext mappingContext) { + arguments.collect { + it.getArgument(typeManager, mappingContext).build() + } + } + /** * Creates an argument to the operation that is a list of a simple type. * The list can not have more than 1 element and that element must be a class. diff --git a/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy b/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy index fa7ae53b..5270eded 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy @@ -8,9 +8,11 @@ import graphql.schema.GraphQLObjectType import graphql.schema.GraphQLOutputType import graphql.schema.TypeResolver import groovy.transform.CompileStatic +import org.grails.datastore.mapping.model.MappingContext import org.grails.datastore.mapping.model.PersistentEntity import org.grails.gorm.graphql.GraphQLEntityHelper import org.grails.gorm.graphql.entity.property.GraphQLDomainProperty +import org.grails.gorm.graphql.entity.property.impl.CustomGraphQLProperty import org.grails.gorm.graphql.entity.property.manager.GraphQLDomainPropertyManager import org.grails.gorm.graphql.response.errors.GraphQLErrorsResponseHandler import org.grails.gorm.graphql.types.GraphQLPropertyType @@ -50,12 +52,17 @@ abstract class AbstractObjectTypeBuilder implements ObjectTypeBuilder { abstract GraphQLPropertyType getType() - protected GraphQLFieldDefinition.Builder buildField(GraphQLDomainProperty prop, String parentType) { + protected GraphQLFieldDefinition.Builder buildField(GraphQLDomainProperty prop, String parentType, MappingContext mapping) { GraphQLFieldDefinition.Builder field = newFieldDefinition() .name(prop.name) .deprecate(prop.deprecationReason) .description(prop.description) + if(prop instanceof CustomGraphQLProperty) { + CustomGraphQLProperty customProp = (CustomGraphQLProperty) prop + field.arguments(customProp.getArguments(typeManager, mapping)) + } + GraphQLOutputType type = (GraphQLOutputType) prop.getGraphQLType(typeManager, type) if (prop.dataFetcher != null) { codeRegistry.dataFetcher( @@ -85,7 +92,7 @@ abstract class AbstractObjectTypeBuilder implements ObjectTypeBuilder { List properties = builder.getProperties(entity) for (GraphQLDomainProperty prop: properties) { if (prop.output) { - fields.add(buildField(prop, NAME).build()) + fields.add(buildField(prop, NAME, entity.mappingContext).build()) } } From bdebdfaebde6f31ec844120ba43f848ad2149764 Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Tue, 10 Nov 2020 08:50:54 -0600 Subject: [PATCH 10/16] Fix static compilation issues when defining custom data fetchers --- .../gorm/graphql/entity/operations/CustomOperation.groovy | 2 +- .../grails-app/domain/grails/test/app/UserRole.groovy | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy index eb53d908..18e0d7c4 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/operations/CustomOperation.groovy @@ -35,7 +35,7 @@ abstract class CustomOperation implements Named, Describable, Deprecata DataFetcher dataFetcher boolean defaultListArguments = false - T dataFetcher(DataFetcher dataFetcher) { + T dataFetcher(DataFetcher dataFetcher) { this.dataFetcher = dataFetcher (T)this } diff --git a/examples/grails-test-app/grails-app/domain/grails/test/app/UserRole.groovy b/examples/grails-test-app/grails-app/domain/grails/test/app/UserRole.groovy index 4bad2259..ef1123d1 100644 --- a/examples/grails-test-app/grails-app/domain/grails/test/app/UserRole.groovy +++ b/examples/grails-test-app/grails-app/domain/grails/test/app/UserRole.groovy @@ -1,9 +1,11 @@ package grails.test.app +import grails.compiler.GrailsCompileStatic import grails.gorm.DetachedCriteria import org.codehaus.groovy.util.HashCodeHelper import org.grails.gorm.graphql.entity.dsl.GraphQLMapping +@GrailsCompileStatic class UserRole implements Serializable { private static final long serialVersionUID = 1 From d76c360c56a1b141dea1b09a4e0eff5b1356abc1 Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Tue, 10 Nov 2020 10:28:46 -0600 Subject: [PATCH 11/16] Tests for field-level arguments --- .../general/custom/property/CustomType.groovy | 22 ++++++ .../general/custom/property/SimpleType.groovy | 14 ++++ .../domain/grails/test/app/ArguedField.groovy | 44 ++++++++++++ .../app/ArguedFieldIntegrationSpec.groovy | 67 +++++++++++++++++++ gradle.properties | 2 +- 5 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 examples/grails-test-app/grails-app/domain/grails/test/app/ArguedField.groovy create mode 100644 examples/grails-test-app/src/integration-test/groovy/grails/test/app/ArguedFieldIntegrationSpec.groovy diff --git a/core/src/test/groovy/org/grails/gorm/graphql/domain/general/custom/property/CustomType.groovy b/core/src/test/groovy/org/grails/gorm/graphql/domain/general/custom/property/CustomType.groovy index d22c8f59..21aa908f 100644 --- a/core/src/test/groovy/org/grails/gorm/graphql/domain/general/custom/property/CustomType.groovy +++ b/core/src/test/groovy/org/grails/gorm/graphql/domain/general/custom/property/CustomType.groovy @@ -79,6 +79,28 @@ class CustomType { } description 'This is a description' } + add('withArgument', 'WithArg') { + argument('arg', String) + type { + field('response', String) + } + } + add('withArgumentList', 'WithArgList') { + argument('arg', [String]) + type { + field('response', String) + } + } + add('withCustomArgument', 'WithCustomArg') { + argument('arg', 'CustomArg') { + accepts { + field('field', String) + } + } + type { + field('response', String) + } + } } } \ No newline at end of file diff --git a/core/src/test/groovy/org/grails/gorm/graphql/domain/general/custom/property/SimpleType.groovy b/core/src/test/groovy/org/grails/gorm/graphql/domain/general/custom/property/SimpleType.groovy index 66f90f5c..8f5dcc3b 100644 --- a/core/src/test/groovy/org/grails/gorm/graphql/domain/general/custom/property/SimpleType.groovy +++ b/core/src/test/groovy/org/grails/gorm/graphql/domain/general/custom/property/SimpleType.groovy @@ -40,6 +40,20 @@ class SimpleType { } add('list', [String]) + + add('withArgument', String) { + argument('arg', String) + } + add('withArgumentList', String) { + argument('arg', [String]) + } + add('withCustomArgument', String) { + argument('arg', 'SimpleArg') { + accepts { + field('field', String) + } + } + } } def methodMissing(String name, Object[] args) { diff --git a/examples/grails-test-app/grails-app/domain/grails/test/app/ArguedField.groovy b/examples/grails-test-app/grails-app/domain/grails/test/app/ArguedField.groovy new file mode 100644 index 00000000..da3430de --- /dev/null +++ b/examples/grails-test-app/grails-app/domain/grails/test/app/ArguedField.groovy @@ -0,0 +1,44 @@ +package grails.test.app + +import grails.compiler.GrailsCompileStatic +import org.grails.gorm.graphql.entity.dsl.GraphQLMapping +import org.grails.gorm.graphql.fetcher.impl.ClosureDataFetchingEnvironment + +@GrailsCompileStatic +class ArguedField { + + String name + + static constraints = { + } + + static graphql = GraphQLMapping.build { + add('withArgument', String) { + input false + argument('ping', String) + dataFetcher { ArguedField af, ClosureDataFetchingEnvironment env -> + env.getArgument('ping') + } + } + add('withArgumentList', String) { + input false + argument('pings', [String]) + dataFetcher { ArguedField af, ClosureDataFetchingEnvironment env -> + List pings = (List)env.getArgument('pings') + "${pings.join('-')}" + } + } + add('withCustomArgument', String) { + input false + argument('ping', 'PingPong') { + accepts { + field('payload', String) + } + } + dataFetcher { ArguedField af, ClosureDataFetchingEnvironment env -> + Map ping = (Map)env.getArgument('ping') + ping["payload"] + } + } + } +} diff --git a/examples/grails-test-app/src/integration-test/groovy/grails/test/app/ArguedFieldIntegrationSpec.groovy b/examples/grails-test-app/src/integration-test/groovy/grails/test/app/ArguedFieldIntegrationSpec.groovy new file mode 100644 index 00000000..8b6f6c4d --- /dev/null +++ b/examples/grails-test-app/src/integration-test/groovy/grails/test/app/ArguedFieldIntegrationSpec.groovy @@ -0,0 +1,67 @@ +package grails.test.app + +import grails.testing.mixin.integration.Integration +import grails.testing.spock.OnceBefore +import org.grails.gorm.graphql.plugin.testing.GraphQLSpec +import spock.lang.Shared +import spock.lang.Specification + +@Integration +class ArguedFieldIntegrationSpec extends Specification implements GraphQLSpec { + + @Shared Long grailsId + + @OnceBefore + void createDomain() { + ArguedField.withTransaction { + grailsId = new ArguedField(name: 'test').save(flush: true).id + } + + } + + void "test a simple argument"() { + when: + def resp = graphQL.graphql(""" + { + arguedField(id: ${grailsId}) { + withArgument(ping: "PONG") + } + } + """) + def obj = resp.body().data.arguedField + + then: + obj.withArgument == "PONG" + } + + void "test a simple argument list"() { + when: + def resp = graphQL.graphql(""" + { + arguedField(id: ${grailsId}) { + withArgumentList(pings: ["P", "O", "N", "G" ]) + } + } + """) + def obj = resp.body().data.arguedField + + then: + obj.withArgumentList == "P-O-N-G" + } + + void "test a custom argument"() { + when: + def resp = graphQL.graphql(""" + { + arguedField(id: ${grailsId}) { + withCustomArgument(ping: {payload: "PONG"}) + } + } + """) + def obj = resp.body().data.arguedField + + then: + obj.withCustomArgument == "PONG" + } + +} diff --git a/gradle.properties b/gradle.properties index cfc95a1b..f80489e1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ title=GORM GraphQL authors=James Kleeh -projectVersion=2.0.1.BUILD-SNAPSHOT +projectVersion=2.0.2.BUILD-SNAPSHOT projectDesc=Generates a GraphQL schema based on entities in GORM projectUrl=https://github.com/grails/gorm-graphql githubSlug=grails/gorm-graphql From a1cd5f15da55a3c7db1335fda15e7030e5a1b0d6 Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Mon, 23 Nov 2020 15:14:57 -0600 Subject: [PATCH 12/16] Build on Arguable See https://github.com/grails/gorm-graphql/pull/56#discussion_r527884980 --- .../types/output/AbstractObjectTypeBuilder.groovy | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy b/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy index 5270eded..cc1576d1 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy @@ -1,6 +1,7 @@ package org.grails.gorm.graphql.types.output import graphql.TypeResolutionEnvironment +import graphql.schema.GraphQLArgument import graphql.schema.GraphQLCodeRegistry import graphql.schema.GraphQLFieldDefinition import graphql.schema.GraphQLInterfaceType @@ -11,6 +12,7 @@ import groovy.transform.CompileStatic import org.grails.datastore.mapping.model.MappingContext import org.grails.datastore.mapping.model.PersistentEntity import org.grails.gorm.graphql.GraphQLEntityHelper +import org.grails.gorm.graphql.entity.dsl.helpers.Arguable import org.grails.gorm.graphql.entity.property.GraphQLDomainProperty import org.grails.gorm.graphql.entity.property.impl.CustomGraphQLProperty import org.grails.gorm.graphql.entity.property.manager.GraphQLDomainPropertyManager @@ -58,9 +60,11 @@ abstract class AbstractObjectTypeBuilder implements ObjectTypeBuilder { .deprecate(prop.deprecationReason) .description(prop.description) - if(prop instanceof CustomGraphQLProperty) { - CustomGraphQLProperty customProp = (CustomGraphQLProperty) prop - field.arguments(customProp.getArguments(typeManager, mapping)) + if(prop instanceof Arguable) { + List arguments = prop.getArguments(typeManager, mapping) + if (!arguments.isEmpty()) { + field.arguments(arguments) + } } GraphQLOutputType type = (GraphQLOutputType) prop.getGraphQLType(typeManager, type) From 6e949fba615ad78911bd554f1aa0385950ef9ffd Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Wed, 9 Dec 2020 11:44:51 -0600 Subject: [PATCH 13/16] Arguments docs - Pushed them up a level to help imply they can be used for both operations and fields - Added a bit to the examples to emphasize usage --- .../docs/guide/customizations/arguments.adoc | 91 +++++++++++++++++++ .../docs/guide/customizations/operations.adoc | 39 +------- docs/src/main/docs/guide/toc.yml | 1 + 3 files changed, 93 insertions(+), 38 deletions(-) create mode 100644 docs/src/main/docs/guide/customizations/arguments.adoc diff --git a/docs/src/main/docs/guide/customizations/arguments.adoc b/docs/src/main/docs/guide/customizations/arguments.adoc new file mode 100644 index 00000000..790407f3 --- /dev/null +++ b/docs/src/main/docs/guide/customizations/arguments.adoc @@ -0,0 +1,91 @@ +== Arguments + +Arguments are how users supply data to your custom operation or field. Arguments support simple types (String, Integer, etc) as well as custom types that you define. + +[source,groovy] +---- +query('authorByName', Author) { + argument('name', String) //To take in a single string + + argument('names', [String]) //To take in a list of strings + + argument('fullName', 'AuthorNameArgument') { //A custom argument + accepts { + field('first', String) + field('last', String) + } + } +} +---- + +The API inside of the last argument block is exactly the same as the API for defining link:#custom[custom properties] with custom types. + +=== Argument Metadata + +GraphQL has the ability to store metadata about arguments to operations. + +[source,groovy] +---- +query('authorByName', Author) { + argument('name', String) { + defaultValue 'John' //Supply a sensible default + + nullable true //Allow a null value (default false) + + description 'The name of the author to search for' + } +} +---- +=== Using Argument Inputs +Within your supplied DataFetcher, arguments can easily be retrieved from their corresponding DataFetchingEnvironment and used as necessary. + +[source,groovy] +---- +class Author { + + String name + + static hasMany = [books: Book] + + static graphql = GraphQLMapping.build { + query('authorByName', Author) { + argument('name', String) + dataFetcher(new DataFetcher<>() { + @Override + Object get(DataFetchingEnvironment environment) { + Author.findByName(environment.getArgument('name')) + } + }) + } + add('booksPublishedBetween', [Book]) { + input(false) + argument('from', Date) + argument('to', Date) + dataFetcher { Author author, ClosureDataFetchingEnvironment environment -> + Date from = environment.getArgument('from') + Date to = environment.getArgument('to') + Book.where { + author == author + published >= from + published <= to + }.list() + } + } + } +} +---- + +The above example would support the following type of query: + +[source,graphql] +---- +query { + authorByName(name: "Herman Melville") { + booksPublishedBetween(from: "1850-01-01", to: "1852-12-31") { + title + pageCount + } + } +} +---- + diff --git a/docs/src/main/docs/guide/customizations/operations.adoc b/docs/src/main/docs/guide/customizations/operations.adoc index 36db563d..c2c52022 100644 --- a/docs/src/main/docs/guide/customizations/operations.adoc +++ b/docs/src/main/docs/guide/customizations/operations.adoc @@ -181,44 +181,6 @@ query('authorByName', Author) { //or [Author] to return a list of authors } ---- -=== Arguments - -Arguments are the way users can supply data to your operation. The argument can be a simple type (String, Integer, etc), or it can also be a custom type that you define. - -[source,groovy] ----- -query('authorByName', Author) { - argument('name', String) //To take in a single string - - argument('names', [String]) //To take in a list of strings - - argument('name', 'AuthorNameArgument') { //A custom argument - accepts { - field('first', String) - field('last', String) - } - } -} ----- - -The API inside of the last argument block is exactly the same as the API for defining link:#custom[custom properties] with custom types. - -==== Argument Metadata - -GraphQL has the ability to store metadata about arguments to operations. - -[source,groovy] ----- -query('authorByName', Author) { - argument('name', String) { - defaultValue 'John' //Supply a sensible default - - nullable true //Allow a null value (default false) - - description 'The name of the author to search for' - } -} ----- === Data Fetcher When creating a custom operation, it is necessary to supply a "data fetcher". The data fetcher is responsible for returning data to GraphQL to be used in generating the response. The data fetcher must be an instance of `graphql.schema.DataFetcher`. @@ -232,6 +194,7 @@ class Author { static hasMany = [books: Book] static graphql = GraphQLMapping.build { + argument('name', String) query('authorByName', Author) { dataFetcher(new DataFetcher<>() { @Override diff --git a/docs/src/main/docs/guide/toc.yml b/docs/src/main/docs/guide/toc.yml index 2d2ff87f..cfb92bd1 100644 --- a/docs/src/main/docs/guide/toc.yml +++ b/docs/src/main/docs/guide/toc.yml @@ -15,6 +15,7 @@ customizations: existing: GORM Properties custom: Custom Properties operations: Operations + arguments: Arguments responseHandlers: Validation Error and Delete Responses namingConvention: Naming Convention configuration: Configuration From 466f9f3b564b637a30eee52c719d7346ed8b6fa9 Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Wed, 9 Dec 2020 16:22:44 -0600 Subject: [PATCH 14/16] Keep original method signature And build field arguments as seperate method to avoid any possible breakages --- .../output/AbstractObjectTypeBuilder.groovy | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy b/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy index cc1576d1..620d58b5 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy @@ -54,19 +54,12 @@ abstract class AbstractObjectTypeBuilder implements ObjectTypeBuilder { abstract GraphQLPropertyType getType() - protected GraphQLFieldDefinition.Builder buildField(GraphQLDomainProperty prop, String parentType, MappingContext mapping) { + protected GraphQLFieldDefinition.Builder buildField(GraphQLDomainProperty prop, String parentType) { GraphQLFieldDefinition.Builder field = newFieldDefinition() .name(prop.name) .deprecate(prop.deprecationReason) .description(prop.description) - if(prop instanceof Arguable) { - List arguments = prop.getArguments(typeManager, mapping) - if (!arguments.isEmpty()) { - field.arguments(arguments) - } - } - GraphQLOutputType type = (GraphQLOutputType) prop.getGraphQLType(typeManager, type) if (prop.dataFetcher != null) { codeRegistry.dataFetcher( @@ -79,6 +72,16 @@ abstract class AbstractObjectTypeBuilder implements ObjectTypeBuilder { field } + protected GraphQLFieldDefinition.Builder addFieldArgs(GraphQLFieldDefinition.Builder field, GraphQLDomainProperty prop, MappingContext mapping) { + if (prop instanceof Arguable) { + List arguments = prop.getArguments(typeManager, mapping) + if (!arguments.isEmpty()) { + field.arguments(arguments) + } + } + return field + } + @Override GraphQLOutputType build(PersistentEntity entity) { @@ -96,7 +99,11 @@ abstract class AbstractObjectTypeBuilder implements ObjectTypeBuilder { List properties = builder.getProperties(entity) for (GraphQLDomainProperty prop: properties) { if (prop.output) { - fields.add(buildField(prop, NAME, entity.mappingContext).build()) + GraphQLFieldDefinition.Builder field = buildField(prop, NAME) + if (prop instanceof Arguable) { + addFieldArgs(field, prop, entity.mappingContext) + } + fields.add(field.build()) } } From be610e5dce26d0d5bf66043309ca61595b09e76b Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Mon, 21 Dec 2020 18:02:54 -0600 Subject: [PATCH 15/16] Fix codenarc violations --- .../gorm/graphql/entity/dsl/helpers/Arguable.groovy | 3 +-- .../graphql/entity/dsl/helpers/ComplexTyped.groovy | 8 +------- .../testing/MockDataFetchingEnvironment.groovy | 2 +- .../types/output/AbstractObjectTypeBuilder.groovy | 11 ++--------- 4 files changed, 5 insertions(+), 19 deletions(-) diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy index 940d34c2..c3d4a7ef 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/Arguable.groovy @@ -74,5 +74,4 @@ trait Arguable extends ExecutesClosures { (T)this } - -} \ No newline at end of file +} diff --git a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy index cd0acdf3..638b6ac5 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/entity/dsl/helpers/ComplexTyped.groovy @@ -1,13 +1,7 @@ package org.grails.gorm.graphql.entity.dsl.helpers -import graphql.schema.GraphQLInputObjectType -import graphql.schema.GraphQLInputType -import graphql.schema.GraphQLList -import graphql.schema.GraphQLNonNull -import graphql.schema.GraphQLOutputType -import graphql.schema.GraphQLType +import graphql.schema.* import groovy.transform.CompileStatic -import graphql.schema.GraphQLObjectType import org.grails.datastore.mapping.model.MappingContext import org.grails.gorm.graphql.entity.fields.ComplexField import org.grails.gorm.graphql.entity.fields.Field diff --git a/core/src/main/groovy/org/grails/gorm/graphql/testing/MockDataFetchingEnvironment.groovy b/core/src/main/groovy/org/grails/gorm/graphql/testing/MockDataFetchingEnvironment.groovy index c34567ac..85f3daff 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/testing/MockDataFetchingEnvironment.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/testing/MockDataFetchingEnvironment.groovy @@ -60,7 +60,7 @@ class MockDataFetchingEnvironment implements DataFetchingEnvironment { @Override Object getArgumentOrDefault(String name, Object defaultValue) { - return arguments.getOrDefault(name, defaultValue) + arguments.getOrDefault(name, defaultValue) } @Override diff --git a/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy b/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy index 620d58b5..d789764b 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy @@ -1,20 +1,13 @@ package org.grails.gorm.graphql.types.output import graphql.TypeResolutionEnvironment -import graphql.schema.GraphQLArgument -import graphql.schema.GraphQLCodeRegistry -import graphql.schema.GraphQLFieldDefinition -import graphql.schema.GraphQLInterfaceType -import graphql.schema.GraphQLObjectType -import graphql.schema.GraphQLOutputType -import graphql.schema.TypeResolver +import graphql.schema.* import groovy.transform.CompileStatic import org.grails.datastore.mapping.model.MappingContext import org.grails.datastore.mapping.model.PersistentEntity import org.grails.gorm.graphql.GraphQLEntityHelper import org.grails.gorm.graphql.entity.dsl.helpers.Arguable import org.grails.gorm.graphql.entity.property.GraphQLDomainProperty -import org.grails.gorm.graphql.entity.property.impl.CustomGraphQLProperty import org.grails.gorm.graphql.entity.property.manager.GraphQLDomainPropertyManager import org.grails.gorm.graphql.response.errors.GraphQLErrorsResponseHandler import org.grails.gorm.graphql.types.GraphQLPropertyType @@ -79,7 +72,7 @@ abstract class AbstractObjectTypeBuilder implements ObjectTypeBuilder { field.arguments(arguments) } } - return field + field } @Override From 7173fbf7948b75c30864570c0eac302a4aaf7a6a Mon Sep 17 00:00:00 2001 From: James Hardwick Date: Wed, 13 Jan 2021 09:44:54 -0600 Subject: [PATCH 16/16] Duplicate check --- .../graphql/types/output/AbstractObjectTypeBuilder.groovy | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy b/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy index d789764b..c350b46f 100644 --- a/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy +++ b/core/src/main/groovy/org/grails/gorm/graphql/types/output/AbstractObjectTypeBuilder.groovy @@ -93,9 +93,7 @@ abstract class AbstractObjectTypeBuilder implements ObjectTypeBuilder { for (GraphQLDomainProperty prop: properties) { if (prop.output) { GraphQLFieldDefinition.Builder field = buildField(prop, NAME) - if (prop instanceof Arguable) { - addFieldArgs(field, prop, entity.mappingContext) - } + addFieldArgs(field, prop, entity.mappingContext) fields.add(field.build()) } }