diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8655013 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +Thumbs.db +.DS_Store +.gradle/ +build/ +.idea/ +*.iml +*.ipr +*.iws +.project +.settings +.classpath diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..54ef8ff --- /dev/null +++ b/build.gradle @@ -0,0 +1,153 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ + +/** + * @author Alexey Zhokhov + */ +buildscript { + repositories { + mavenLocal() + jcenter() + maven { url 'https://plugins.gradle.org/m2/' } + maven { url 'http://repo.spring.io/plugins-release' } + } + dependencies { + classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' + } +} + +subprojects { + apply plugin: 'idea' + apply plugin: 'java' + apply plugin: 'maven' + apply plugin: 'maven-publish' + apply plugin: 'com.jfrog.bintray' + apply plugin: 'groovy' + + version = projectVersion + group = 'com.graphql-java' + + repositories { + mavenLocal() + jcenter() + maven { url 'https://dl.bintray.com/andimarek/graphql-java/' } + } + + dependencies { + testCompile 'org.spockframework:spock-core:1.1-groovy-2.4' + testCompile 'org.codehaus.groovy:groovy-all:2.4.12' + } + + idea { + module { + downloadJavadoc = true + downloadSources = true + } + } + + compileJava { + sourceCompatibility = 1.8 + targetCompatibility = 1.8 + } + + if (it.name != 'graphql-datetime-sample-app') { + jar { + from 'LICENSE' + } + + task sourcesJar(type: Jar) { + dependsOn classes + classifier 'sources' + from sourceSets.main.allSource + } + + task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir + } + + artifacts { + archives sourcesJar + archives javadocJar + } + + publishing { + publications { + mainProjectPublication(MavenPublication) { + version version + from components.java + + artifact sourcesJar { + classifier 'sources' + } + artifact javadocJar { + classifier 'javadoc' + } + + pom.withXml { + asNode().children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + name projectName + description projectDescription + url projectGitRepoUrl + scm { + url projectGitRepoUrl + connection projectGitRepoUrl + developerConnection projectGitRepoUrl + } + licenses { + license { + name projectLicense + url projectLicenseUrl + distribution 'repo' + } + } + developers { + developer { + id 'donbeave' + name 'Alexey Zhokhov' + } + } + } + } + } + } + } + + /* + bintray { + user = System.env.BINTRAY_USER ?: project.findProperty('BINTRAY_USER') ?: '' + key = System.env.BINTRAY_KEY ?: project.findProperty('BINTRAY_KEY') ?: '' + publications = ['mainProjectPublication'] + publish = true + pkg { + repo = 'maven' + name = projectName + desc = projectDescription + licenses = [projectLicense] + vcsUrl = projectGitRepoUrl + version { + name = project.version + } + } + } + */ + } +} + +task wrapper(type: Wrapper) { + gradleVersion = gradleWrapperVersion +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..b6d7072 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,19 @@ +gradleWrapperVersion=4.0 +graphqlJavaVersion=2017-07-06T09-33-35 +graphqlSpringBootVersion=3.5.0 +graphqlJavaToolsVersion=3.1.3 +springBootVersion=1.5.4.RELEASE +# +projectVersion=1.0.0-SNAPSHOT +projectName=graphql-java-datetime +projectDescription=The set of RFC 3339 compliant date/time scalar types for GraphQL Java implementation +projectGitRepoUrl=https://github.com/donbeave/graphql-java-datetime +projectLicense=Apache-2.0 +projectLicenseUrl=https://github.com/donbeave/graphql-java-datetime/blob/master/LICENSE +# +org.gradle.caching=true +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.parallel.intra=true +org.gradle.configureondemand=true +org.gradle.jvmargs=-Dfile.encoding=UTF-8 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9cdc604 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..9c153ac --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sun Jul 09 18:32:24 HKT 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..4453cce --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +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="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +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 + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +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 + 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 + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((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" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +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 new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@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= + +@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 + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +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% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/graphql-datetime-autoconfigure/build.gradle b/graphql-datetime-autoconfigure/build.gradle new file mode 100644 index 0000000..cf55b86 --- /dev/null +++ b/graphql-datetime-autoconfigure/build.gradle @@ -0,0 +1,29 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ + +/** + * @author Alexey Zhokhov + */ +dependencies { + compile "com.graphql-java:graphql-spring-boot-autoconfigure:$graphqlSpringBootVersion" + compile "com.graphql-java:graphql-spring-boot-starter:$graphqlSpringBootVersion" + compile "com.graphql-java:graphql-java-tools:$graphqlJavaToolsVersion" + compile(project(':graphql-java-datetime')) + + testCompile "org.springframework.boot:spring-boot-starter-web:$springBootVersion" + testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion" + testCompile "org.springframework.boot:spring-boot-test:$springBootVersion" +} diff --git a/graphql-datetime-autoconfigure/src/main/java/graphql/datetime/boot/GraphQLDateTimeAutoConfiguration.java b/graphql-datetime-autoconfigure/src/main/java/graphql/datetime/boot/GraphQLDateTimeAutoConfiguration.java new file mode 100644 index 0000000..7b873ba --- /dev/null +++ b/graphql-datetime-autoconfigure/src/main/java/graphql/datetime/boot/GraphQLDateTimeAutoConfiguration.java @@ -0,0 +1,59 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime.boot; + +import com.oembedler.moon.graphql.boot.GraphQLJavaToolsAutoConfiguration; +import graphql.datetime.GraphQLDate; +import graphql.datetime.GraphQLLocalDate; +import graphql.datetime.GraphQLLocalDateTime; +import graphql.datetime.GraphQLLocalTime; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Alexey Zhokhov + */ +@Configuration +@AutoConfigureBefore({GraphQLJavaToolsAutoConfiguration.class}) +public class GraphQLDateTimeAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public GraphQLDate graphQLDate() { + return new GraphQLDate(); + } + + @Bean + @ConditionalOnMissingBean + public GraphQLLocalDate graphQLLocalDate() { + return new GraphQLLocalDate(); + } + + @Bean + @ConditionalOnMissingBean + public GraphQLLocalDateTime graphQLLocalDateTime() { + return new GraphQLLocalDateTime(); + } + + @Bean + @ConditionalOnMissingBean + public GraphQLLocalTime graphQLLocalTime() { + return new GraphQLLocalTime(); + } + +} diff --git a/graphql-datetime-autoconfigure/src/main/resources/META-INF/spring.factories b/graphql-datetime-autoconfigure/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..faeeec9 --- /dev/null +++ b/graphql-datetime-autoconfigure/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +graphql.datetime.boot.GraphQLDateTimeAutoConfiguration diff --git a/graphql-datetime-autoconfigure/src/test/groovy/graphql/datetime/boot/test/GraphQLDateTimeAutoConfigurationSpec.groovy b/graphql-datetime-autoconfigure/src/test/groovy/graphql/datetime/boot/test/GraphQLDateTimeAutoConfigurationSpec.groovy new file mode 100644 index 0000000..98b5bfe --- /dev/null +++ b/graphql-datetime-autoconfigure/src/test/groovy/graphql/datetime/boot/test/GraphQLDateTimeAutoConfigurationSpec.groovy @@ -0,0 +1,83 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime.boot.test + +import graphql.GraphQL +import graphql.datetime.GraphQLDate +import graphql.datetime.GraphQLLocalDate +import graphql.datetime.GraphQLLocalDateTime +import graphql.datetime.GraphQLLocalTime +import graphql.schema.GraphQLSchema +import org.springframework.context.support.AbstractApplicationContext +import spock.lang.Specification + +/** + * @author Alexey Zhokhov + */ +class GraphQLDateTimeAutoConfigurationSpec extends Specification { + + AbstractApplicationContext context + + def setup() { + context = ContextHelper.load() + } + + def cleanup() { + if (context) { + context.close() + context = null + } + } + + def "test"() { + given: + String query = """ +{ + echo { + date + localDate + localDateTime + localTime + } +} +""" + + when: + this.context = ContextHelper.load() + + then: + context.getBean(GraphQLSchema.class) + context.getBean(GraphQLDate.class) + context.getBean(GraphQLLocalDate.class) + context.getBean(GraphQLLocalDateTime.class) + context.getBean(GraphQLLocalTime.class) + + when: + GraphQL graphQL = GraphQL.newGraphQL(context.getBean(GraphQLSchema.class)).build() + Map result = graphQL.execute(query).getData() + + then: + result == [ + echo: [ + date : '2017-07-10T06:12:46.754Z', + localDate : '2017-01-01', + localDateTime: '2017-01-01T00:00:00Z', + localTime : '00:00:00' + ] + ] + } + +} diff --git a/graphql-datetime-autoconfigure/src/test/groovy/graphql/datetime/boot/test/GraphQLServletSpec.groovy b/graphql-datetime-autoconfigure/src/test/groovy/graphql/datetime/boot/test/GraphQLServletSpec.groovy new file mode 100644 index 0000000..0c28d61 --- /dev/null +++ b/graphql-datetime-autoconfigure/src/test/groovy/graphql/datetime/boot/test/GraphQLServletSpec.groovy @@ -0,0 +1,91 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime.boot.test + +import com.fasterxml.jackson.databind.ObjectMapper +import graphql.schema.GraphQLSchema +import graphql.servlet.GraphQLServlet +import graphql.servlet.SimpleGraphQLServlet +import org.springframework.context.support.AbstractApplicationContext +import org.springframework.mock.web.MockHttpServletRequest +import org.springframework.mock.web.MockHttpServletResponse +import spock.lang.Shared +import spock.lang.Specification + +/** + * @author Alexey Zhokhov + */ +class GraphQLServletSpec extends Specification { + + public static final String CONTENT_TYPE_JSON_UTF8 = 'application/json;charset=UTF-8' + + @Shared + ObjectMapper mapper = new ObjectMapper() + + AbstractApplicationContext context + MockHttpServletRequest request + MockHttpServletResponse response + + def setup() { + context = ContextHelper.load() + request = new MockHttpServletRequest() + response = new MockHttpServletResponse() + } + + def cleanup() { + if (context) { + context.close() + context = null + } + } + + def "test"() { + given: + GraphQLSchema graphQLSchema = context.getBean(GraphQLSchema.class) + GraphQLServlet servlet = new SimpleGraphQLServlet(graphQLSchema) + + String query = """ +{ + echo { + date + localDate + localDateTime + localTime + } +} +""" + + when: + servlet.executeQuery(query) + + then: + response.getStatus() == 200 + response.getContentType() == CONTENT_TYPE_JSON_UTF8 + responseContent.data == [ + echo: [ + date : '2017-07-10T06:12:46.754Z', + localDate : '2017-01-01', + localDateTime: '2017-01-01T00:00:00Z', + localTime : '00:00:00' + ] + ] + } + + private Map getResponseContent() { + mapper.readValue(response.getContentAsByteArray(), Map) + } + +} diff --git a/graphql-datetime-autoconfigure/src/test/java/graphql/datetime/boot/test/ContextHelper.java b/graphql-datetime-autoconfigure/src/test/java/graphql/datetime/boot/test/ContextHelper.java new file mode 100644 index 0000000..4ea0c10 --- /dev/null +++ b/graphql-datetime-autoconfigure/src/test/java/graphql/datetime/boot/test/ContextHelper.java @@ -0,0 +1,66 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime.boot.test; + +import com.oembedler.moon.graphql.boot.GraphQLJavaToolsAutoConfiguration; +import graphql.datetime.GraphQLDate; +import graphql.datetime.GraphQLLocalDate; +import graphql.datetime.GraphQLLocalDateTime; +import graphql.datetime.GraphQLLocalTime; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.AnnotationConfigRegistry; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.AbstractApplicationContext; + +/** + * @author Alexey Zhokhov + */ +public class ContextHelper { + + @Configuration + @ComponentScan("graphql.datetime.boot") + static class BaseConfiguration { + + // initialize date time types here + @Autowired(required = false) GraphQLDate graphQLDate; + @Autowired(required = false) GraphQLLocalDate graphQLLocalDate; + @Autowired(required = false) GraphQLLocalDateTime graphQLLocalDateTime; + @Autowired(required = false) GraphQLLocalTime graphQLLocalTime; + + } + + static public AbstractApplicationContext load() { + AbstractApplicationContext context; + + try { + context = AnnotationConfigApplicationContext.class.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + + AnnotationConfigRegistry registry = (AnnotationConfigRegistry) context; + + registry.register(BaseConfiguration.class); + registry.register(GraphQLJavaToolsAutoConfiguration.class); + + context.refresh(); + + return context; + } + +} diff --git a/graphql-datetime-autoconfigure/src/test/java/graphql/datetime/boot/test/resolvers/Query.java b/graphql-datetime-autoconfigure/src/test/java/graphql/datetime/boot/test/resolvers/Query.java new file mode 100644 index 0000000..3c4526c --- /dev/null +++ b/graphql-datetime-autoconfigure/src/test/java/graphql/datetime/boot/test/resolvers/Query.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime.boot.test.resolvers; + +import com.coxautodev.graphql.tools.GraphQLRootResolver; +import org.springframework.stereotype.Component; + +/** + * @author Alexey Zhokhov + */ +@Component +public class Query implements GraphQLRootResolver { + + public ResponseType echo() { + return new ResponseType(); + } + +} \ No newline at end of file diff --git a/graphql-datetime-autoconfigure/src/test/java/graphql/datetime/boot/test/resolvers/ResponseType.java b/graphql-datetime-autoconfigure/src/test/java/graphql/datetime/boot/test/resolvers/ResponseType.java new file mode 100644 index 0000000..17427b7 --- /dev/null +++ b/graphql-datetime-autoconfigure/src/test/java/graphql/datetime/boot/test/resolvers/ResponseType.java @@ -0,0 +1,56 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime.boot.test.resolvers; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Date; + +/** + * @author Alexey Zhokhov + */ +public class ResponseType { + + private Date date; + private LocalDate localDate; + private LocalDateTime localDateTime; + private LocalTime localTime; + + public ResponseType() { + date = new Date(1499667166754L); + localDate = LocalDate.of(2017, 1, 1); + localTime = LocalTime.MIDNIGHT; + localDateTime = LocalDateTime.of(localDate, localTime); + } + + public Date getDate() { + return date; + } + + public LocalDate getLocalDate() { + return localDate; + } + + public LocalDateTime getLocalDateTime() { + return localDateTime; + } + + public LocalTime getLocalTime() { + return localTime; + } + +} diff --git a/graphql-datetime-autoconfigure/src/test/resources/graphqlDateTime.graphqls b/graphql-datetime-autoconfigure/src/test/resources/graphqlDateTime.graphqls new file mode 100644 index 0000000..ce8cb43 --- /dev/null +++ b/graphql-datetime-autoconfigure/src/test/resources/graphqlDateTime.graphqls @@ -0,0 +1,31 @@ +# +# Copyright 2017 Alexey Zhokhov +# +# 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 +# +# http://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. +# + +scalar Date +scalar LocalDate +scalar LocalDateTime +scalar LocalTime + +type Query { + echo: Response +} + +type Response { + date: Date + localDate: LocalDate + localDateTime: LocalDateTime + localTime: LocalTime +} diff --git a/graphql-datetime-autoconfigure/src/test/resources/logback-spring.xml b/graphql-datetime-autoconfigure/src/test/resources/logback-spring.xml new file mode 100644 index 0000000..f9b15fc --- /dev/null +++ b/graphql-datetime-autoconfigure/src/test/resources/logback-spring.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graphql-datetime-spring-boot-starter/build.gradle b/graphql-datetime-spring-boot-starter/build.gradle new file mode 100644 index 0000000..ecaa391 --- /dev/null +++ b/graphql-datetime-spring-boot-starter/build.gradle @@ -0,0 +1,22 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ + +/** + * @author Alexey Zhokhov + */ +dependencies { + compile(project(':graphql-datetime-autoconfigure')) +} diff --git a/graphql-java-datetime/build.gradle b/graphql-java-datetime/build.gradle new file mode 100644 index 0000000..34f96e4 --- /dev/null +++ b/graphql-java-datetime/build.gradle @@ -0,0 +1,22 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ + +/** + * @author Alexey Zhokhov + */ +dependencies { + compile "com.graphql-java:graphql-java:$graphqlJavaVersion" +} diff --git a/graphql-java-datetime/src/main/java/graphql/datetime/DateTimeHelper.java b/graphql-java-datetime/src/main/java/graphql/datetime/DateTimeHelper.java new file mode 100644 index 0000000..168b1f7 --- /dev/null +++ b/graphql-java-datetime/src/main/java/graphql/datetime/DateTimeHelper.java @@ -0,0 +1,119 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; + +/** + * @author Alexey Zhokhov + */ +public class DateTimeHelper { + + public static final CopyOnWriteArrayList DATE_FORMATTERS = new CopyOnWriteArrayList<>(); + + static { + DATE_FORMATTERS.add(DateTimeFormatter.ISO_INSTANT.withZone(ZoneOffset.UTC)); + DATE_FORMATTERS.add(DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneOffset.UTC)); + DATE_FORMATTERS.add(DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneOffset.UTC)); + } + + // ISO_8601 + public static String toISOString(LocalDateTime dateTime) { + Objects.requireNonNull(dateTime, "dateTime"); + + return DateTimeFormatter.ISO_INSTANT.format(ZonedDateTime.of(dateTime, ZoneOffset.UTC)); + } + + public static String toISOString(LocalDate date) { + Objects.requireNonNull(date, "date"); + + return DateTimeFormatter.ISO_LOCAL_DATE.format(date); + } + + public static String toISOString(LocalTime time) { + Objects.requireNonNull(time, "time"); + + return DateTimeFormatter.ISO_LOCAL_TIME.format(time); + } + + public static String toISOString(Date date) { + Objects.requireNonNull(date, "date"); + + return toISOString(toLocalDateTime(date)); + } + + public static LocalDateTime toLocalDateTime(Date date) { + Objects.requireNonNull(date, "date"); + + return date.toInstant().atZone(ZoneOffset.UTC).toLocalDateTime(); + } + + public static Date toDate(LocalDate date) { + Objects.requireNonNull(date, "date"); + + return toDate(date.atStartOfDay()); + } + + public static Date toDate(LocalDateTime dateTime) { + Objects.requireNonNull(dateTime, "dateTime"); + + return Date.from(dateTime.atZone(ZoneOffset.UTC).toInstant()); + } + + public static LocalDateTime parseDate(String date) { + Objects.requireNonNull(date, "date"); + + for (DateTimeFormatter formatter : DATE_FORMATTERS) { + try { + // equals ISO_LOCAL_DATE + if (formatter.equals(DATE_FORMATTERS.get(2))) { + LocalDate localDate = LocalDate.parse(date, formatter); + + return localDate.atStartOfDay(); + } else { + return LocalDateTime.parse(date, formatter); + } + } catch (java.time.format.DateTimeParseException ignored) { + } + } + + return null; + } + + public static Date createDate(int year, int month, int day) { + return createDate(year, month, day, 0, 0, 0, 0); + } + + public static Date createDate(int year, int month, int day, int hours, int min, int sec) { + return createDate(year, month, day, hours, min, sec, 0); + } + + public static Date createDate(int year, int month, int day, int hours, int min, int sec, int millis) { + long nanos = TimeUnit.MILLISECONDS.toNanos(millis); + LocalDateTime localDateTime = LocalDateTime.of(year, month, day, hours, min, sec, (int) nanos); + return DateTimeHelper.toDate(localDateTime); + } + +} diff --git a/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLDate.java b/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLDate.java new file mode 100644 index 0000000..ad9bac7 --- /dev/null +++ b/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLDate.java @@ -0,0 +1,81 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime; + +import graphql.language.StringValue; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; + +import java.time.LocalDateTime; +import java.util.Date; + +import static graphql.datetime.DateTimeHelper.parseDate; +import static graphql.datetime.DateTimeHelper.toDate; +import static graphql.datetime.DateTimeHelper.toISOString; + +/** + * @author Alexey Zhokhov + */ +public class GraphQLDate extends GraphQLScalarType { + + public GraphQLDate() { + super("Date", "Date type", new Coercing() { + private Date convertImpl(Object input) { + if (input instanceof String) { + LocalDateTime localDateTime = parseDate((String) input); + + if (localDateTime != null) { + return toDate(localDateTime); + } + } + return null; + } + + @Override + public String serialize(Object input) { + if (input instanceof Date) { + return toISOString((Date) input); + } else { + Date result = convertImpl(input); + if (result == null) { + throw new CoercingSerializeException("Invalid value '" + input + "' for Date"); + } + return toISOString(result); + } + } + + @Override + public Date parseValue(Object input) { + Date result = convertImpl(input); + if (result == null) { + throw new CoercingParseValueException("Invalid value '" + input + "' for Date"); + } + return result; + } + + @Override + public Date parseLiteral(Object input) { + if (!(input instanceof StringValue)) return null; + String value = ((StringValue) input).getValue(); + Date result = convertImpl(value); + return result; + } + }); + } + +} diff --git a/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLLocalDate.java b/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLLocalDate.java new file mode 100644 index 0000000..2628857 --- /dev/null +++ b/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLLocalDate.java @@ -0,0 +1,80 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime; + +import graphql.language.StringValue; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +import static graphql.datetime.DateTimeHelper.parseDate; +import static graphql.datetime.DateTimeHelper.toISOString; + +/** + * @author Alexey Zhokhov + */ +public class GraphQLLocalDate extends GraphQLScalarType { + + public GraphQLLocalDate() { + super("LocalDate", "Local Date type", new Coercing() { + private LocalDate convertImpl(Object input) { + if (input instanceof String) { + LocalDateTime localDateTime = parseDate((String) input); + + if (localDateTime != null) { + return localDateTime.toLocalDate(); + } + } + return null; + } + + @Override + public String serialize(Object input) { + if (input instanceof LocalDate) { + return toISOString((LocalDate) input); + } else { + LocalDate result = convertImpl(input); + if (result == null) { + throw new CoercingSerializeException("Invalid value '" + input + "' for LocalDate"); + } + return toISOString(result); + } + } + + @Override + public LocalDate parseValue(Object input) { + LocalDate result = convertImpl(input); + if (result == null) { + throw new CoercingParseValueException("Invalid value '" + input + "' for LocalDate"); + } + return result; + } + + @Override + public LocalDate parseLiteral(Object input) { + if (!(input instanceof StringValue)) return null; + String value = ((StringValue) input).getValue(); + LocalDate result = convertImpl(value); + return result; + } + }); + } + +} diff --git a/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLLocalDateTime.java b/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLLocalDateTime.java new file mode 100644 index 0000000..c254081 --- /dev/null +++ b/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLLocalDateTime.java @@ -0,0 +1,77 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime; + +import graphql.language.StringValue; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; + +import java.time.LocalDateTime; + +import static graphql.datetime.DateTimeHelper.parseDate; +import static graphql.datetime.DateTimeHelper.toISOString; + +/** + * @author Alexey Zhokhov + */ +public class GraphQLLocalDateTime extends GraphQLScalarType { + + public GraphQLLocalDateTime() { + super("LocalDateTime", "Local Date Time type", new Coercing() { + private LocalDateTime convertImpl(Object input) { + if (input instanceof String) { + LocalDateTime localDateTime = parseDate((String) input); + + return localDateTime; + } + return null; + } + + @Override + public String serialize(Object input) { + if (input instanceof LocalDateTime) { + return toISOString((LocalDateTime) input); + } else { + LocalDateTime result = convertImpl(input); + if (result == null) { + throw new CoercingSerializeException("Invalid value '" + input + "' for LocalDateTime"); + } + return toISOString(result); + } + } + + @Override + public LocalDateTime parseValue(Object input) { + LocalDateTime result = convertImpl(input); + if (result == null) { + throw new CoercingParseValueException("Invalid value '" + input + "' for LocalDateTime"); + } + return result; + } + + @Override + public LocalDateTime parseLiteral(Object input) { + if (!(input instanceof StringValue)) return null; + String value = ((StringValue) input).getValue(); + LocalDateTime result = convertImpl(value); + return result; + } + }); + } + +} diff --git a/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLLocalTime.java b/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLLocalTime.java new file mode 100644 index 0000000..042ff7e --- /dev/null +++ b/graphql-java-datetime/src/main/java/graphql/datetime/GraphQLLocalTime.java @@ -0,0 +1,82 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime; + +import graphql.language.StringValue; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; + +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +import static graphql.datetime.DateTimeHelper.toISOString; + +/** + * @author Alexey Zhokhov + */ +public class GraphQLLocalTime extends GraphQLScalarType { + + public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_TIME.withZone(ZoneOffset.UTC); + + public GraphQLLocalTime() { + super("LocalTime", "Local Time type", new Coercing() { + private LocalTime convertImpl(Object input) { + if (input instanceof String) { + try { + return LocalTime.parse((String) input, FORMATTER); + } catch (DateTimeParseException ignored) { + } + } + return null; + } + + @Override + public String serialize(Object input) { + if (input instanceof LocalTime) { + return toISOString((LocalTime) input); + } else { + LocalTime result = convertImpl(input); + if (result == null) { + throw new CoercingSerializeException("Invalid value '" + input + "' for LocalTime"); + } + return toISOString(result); + } + } + + @Override + public LocalTime parseValue(Object input) { + LocalTime result = convertImpl(input); + if (result == null) { + throw new CoercingParseValueException("Invalid value '" + input + "' for LocalTime"); + } + return result; + } + + @Override + public LocalTime parseLiteral(Object input) { + if (!(input instanceof StringValue)) return null; + String value = ((StringValue) input).getValue(); + LocalTime result = convertImpl(value); + return result; + } + }); + } + +} diff --git a/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLDateTest.groovy b/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLDateTest.groovy new file mode 100644 index 0000000..cba11fa --- /dev/null +++ b/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLDateTest.groovy @@ -0,0 +1,108 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime + +import graphql.language.StringValue +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Specification +import spock.lang.Unroll + +import static DateTimeHelper.createDate + +/** + * @author Alexey Zhokhov + */ +class GraphQLDateTest extends Specification { + + @Unroll + def "Date parse literal #literal.value as #result"() { + expect: + new GraphQLDate().getCoercing().parseLiteral(literal) == result + + where: + literal | result + new StringValue('2017-07-09T11:54:42.277Z') | createDate(2017, 7, 9, 11, 54, 42, 277) + new StringValue('2017-07-09T13:14:45.947Z') | createDate(2017, 7, 9, 13, 14, 45, 947) + new StringValue('2017-07-09T11:54:42Z') | createDate(2017, 7, 9, 11, 54, 42) + new StringValue('2017-07-09') | createDate(2017, 7, 9) + } + + @Unroll + def "Date returns null for invalid #literal"() { + expect: + new GraphQLDate().getCoercing().parseLiteral(literal) == null + + where: + literal | _ + new StringValue("not a date") | _ + } + + @Unroll + def "Date serialize #value into #result (#result.class)"() { + expect: + new GraphQLDate().getCoercing().serialize(value) == result + + where: + value | result + createDate(2017, 7, 9, 11, 54, 42, 277) | '2017-07-09T11:54:42.277Z' + createDate(2017, 7, 9, 13, 14, 45, 947) | '2017-07-09T13:14:45.947Z' + createDate(2017, 7, 9, 11, 54, 42) | '2017-07-09T11:54:42Z' + createDate(2017, 7, 9) | '2017-07-09T00:00:00Z' + } + + @Unroll + def "serialize throws exception for invalid input #value"() { + when: + new GraphQLDate().getCoercing().serialize(value) + then: + thrown(CoercingSerializeException) + + where: + value | _ + '' | _ + 'not a date' | _ + new Object() | _ + } + + @Unroll + def "Date parse #value into #result (#result.class)"() { + expect: + new GraphQLDate().getCoercing().parseValue(value) == result + + where: + value | result + '2017-07-09T11:54:42.277Z' | createDate(2017, 7, 9, 11, 54, 42, 277) + '2017-07-09T13:14:45.947Z' | createDate(2017, 7, 9, 13, 14, 45, 947) + '2017-07-09T11:54:42Z' | createDate(2017, 7, 9, 11, 54, 42) + '2017-07-09' | createDate(2017, 7, 9) + } + + @Unroll + def "parseValue throws exception for invalid input #value"() { + when: + new GraphQLDate().getCoercing().parseValue(value) + then: + thrown(CoercingParseValueException) + + where: + value | _ + '' | _ + 'not a date' | _ + new Object() | _ + } + +} diff --git a/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLLocalDateTest.groovy b/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLLocalDateTest.groovy new file mode 100644 index 0000000..500bc49 --- /dev/null +++ b/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLLocalDateTest.groovy @@ -0,0 +1,99 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime + +import graphql.language.StringValue +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Specification +import spock.lang.Unroll + +import java.time.LocalDate + +/** + * @author Alexey Zhokhov + */ +class GraphQLLocalDateTest extends Specification { + + @Unroll + def "Date parse literal #literal.value as #result"() { + expect: + new GraphQLLocalDate().getCoercing().parseLiteral(literal) == result + + where: + literal | result + new StringValue('2017-07-09') | LocalDate.of(2017, 7, 9) + } + + @Unroll + def "Date returns null for invalid #literal"() { + expect: + new GraphQLLocalDate().getCoercing().parseLiteral(literal) == null + + where: + literal | _ + new StringValue("not a date") | _ + } + + @Unroll + def "Date serialize #value into #result (#result.class)"() { + expect: + new GraphQLLocalDate().getCoercing().serialize(value) == result + + where: + value | result + LocalDate.of(2017, 7, 9) | '2017-07-09' + } + + @Unroll + def "serialize throws exception for invalid input #value"() { + when: + new GraphQLLocalDate().getCoercing().serialize(value) + then: + thrown(CoercingSerializeException) + + where: + value | _ + '' | _ + 'not a date' | _ + new Object() | _ + } + + @Unroll + def "Date parse #value into #result (#result.class)"() { + expect: + new GraphQLLocalDate().getCoercing().parseValue(value) == result + + where: + value | result + '2017-07-09' | LocalDate.of(2017, 7, 9) + } + + @Unroll + def "parseValue throws exception for invalid input #value"() { + when: + new GraphQLLocalDate().getCoercing().parseValue(value) + then: + thrown(CoercingParseValueException) + + where: + value | _ + '' | _ + 'not a date' | _ + new Object() | _ + } + +} diff --git a/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLLocalDateTimeTest.groovy b/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLLocalDateTimeTest.groovy new file mode 100644 index 0000000..11e6fab --- /dev/null +++ b/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLLocalDateTimeTest.groovy @@ -0,0 +1,112 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime + +import graphql.language.StringValue +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Specification +import spock.lang.Unroll + +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime + +import static java.util.concurrent.TimeUnit.MILLISECONDS + +/** + * @author Alexey Zhokhov + */ +class GraphQLLocalDateTimeTest extends Specification { + + @Unroll + def "Date parse literal #literal.value as #result"() { + expect: + new GraphQLLocalDateTime().getCoercing().parseLiteral(literal) == result + + where: + literal | result + new StringValue('2017-07-09T11:54:42.277Z') | LocalDateTime.of(2017, 7, 9, 11, 54, 42, (int) MILLISECONDS.toNanos(277)) + new StringValue('2017-07-09T13:14:45.947Z') | LocalDateTime.of(2017, 7, 9, 13, 14, 45, (int) MILLISECONDS.toNanos(947)) + new StringValue('2017-07-09T11:54:42Z') | LocalDateTime.of(2017, 7, 9, 11, 54, 42) + new StringValue('2017-07-09') | LocalDateTime.of(LocalDate.of(2017, 7, 9), LocalTime.MIDNIGHT) + } + + @Unroll + def "Date returns null for invalid #literal"() { + expect: + new GraphQLLocalDateTime().getCoercing().parseLiteral(literal) == null + + where: + literal | _ + new StringValue("not a date") | _ + } + + @Unroll + def "Date serialize #value into #result (#result.class)"() { + expect: + new GraphQLLocalDateTime().getCoercing().serialize(value) == result + + where: + value | result + LocalDateTime.of(2017, 7, 9, 11, 54, 42, (int) MILLISECONDS.toNanos(277)) | '2017-07-09T11:54:42.277Z' + LocalDateTime.of(2017, 7, 9, 13, 14, 45, (int) MILLISECONDS.toNanos(947)) | '2017-07-09T13:14:45.947Z' + LocalDateTime.of(2017, 7, 9, 11, 54, 42) | '2017-07-09T11:54:42Z' + LocalDateTime.of(LocalDate.of(2017, 7, 9), LocalTime.MIDNIGHT) | '2017-07-09T00:00:00Z' + } + + @Unroll + def "serialize throws exception for invalid input #value"() { + when: + new GraphQLLocalDateTime().getCoercing().serialize(value) + then: + thrown(CoercingSerializeException) + + where: + value | _ + '' | _ + 'not a date' | _ + new Object() | _ + } + + @Unroll + def "Date parse #value into #result (#result.class)"() { + expect: + new GraphQLLocalDateTime().getCoercing().parseValue(value) == result + + where: + value | result + '2017-07-09T11:54:42.277Z' | LocalDateTime.of(2017, 7, 9, 11, 54, 42, (int) MILLISECONDS.toNanos(277)) + '2017-07-09T13:14:45.947Z' | LocalDateTime.of(2017, 7, 9, 13, 14, 45, (int) MILLISECONDS.toNanos(947)) + '2017-07-09T11:54:42Z' | LocalDateTime.of(2017, 7, 9, 11, 54, 42) + '2017-07-09' | LocalDateTime.of(LocalDate.of(2017, 7, 9), LocalTime.MIDNIGHT) + } + + @Unroll + def "parseValue throws exception for invalid input #value"() { + when: + new GraphQLLocalDateTime().getCoercing().parseValue(value) + then: + thrown(CoercingParseValueException) + + where: + value | _ + '' | _ + 'not a date' | _ + new Object() | _ + } + +} diff --git a/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLLocalTimeTest.groovy b/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLLocalTimeTest.groovy new file mode 100644 index 0000000..aadff46 --- /dev/null +++ b/graphql-java-datetime/src/test/groovy/graphql/datetime/GraphQLLocalTimeTest.groovy @@ -0,0 +1,108 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ +package graphql.datetime + +import graphql.language.StringValue +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Specification +import spock.lang.Unroll + +import java.time.LocalTime +import java.util.concurrent.TimeUnit + +/** + * @author Alexey Zhokhov + */ +class GraphQLLocalTimeTest extends Specification { + + @Unroll + def "Date parse literal #literal.value as #result"() { + expect: + new GraphQLLocalTime().getCoercing().parseLiteral(literal) == result + + where: + literal | result + new StringValue('00:00:00') | LocalTime.MIDNIGHT + new StringValue('10:15:30') | LocalTime.of(10, 15, 30) + new StringValue('17:59:59') | LocalTime.of(17, 59, 59) + } + + @Unroll + def "Date returns null for invalid #literal"() { + expect: + new GraphQLLocalTime().getCoercing().parseLiteral(literal) == null + + where: + literal | _ + new StringValue("not a time") | _ + } + + @Unroll + def "Date serialize #value into #result (#result.class)"() { + expect: + new GraphQLLocalTime().getCoercing().serialize(value) == result + + where: + value | result + LocalTime.MIDNIGHT | '00:00:00' + LocalTime.of(10, 15, 30) | '10:15:30' + LocalTime.of(17, 59, 59) | '17:59:59' + LocalTime.of(17, 59, 59, (int) TimeUnit.MILLISECONDS.toNanos(277)) | '17:59:59.277' + } + + @Unroll + def "serialize throws exception for invalid input #value"() { + when: + new GraphQLLocalTime().getCoercing().serialize(value) + then: + thrown(CoercingSerializeException) + + where: + value | _ + '' | _ + 'not a time' | _ + new Object() | _ + } + + @Unroll + def "Date parse #value into #result (#result.class)"() { + expect: + new GraphQLLocalTime().getCoercing().parseValue(value) == result + + where: + value | result + '00:00:00' | LocalTime.MIDNIGHT + '10:15:30' | LocalTime.of(10, 15, 30) + '17:59:59' | LocalTime.of(17, 59, 59) + '17:59:59.277' | LocalTime.of(17, 59, 59, (int) TimeUnit.MILLISECONDS.toNanos(277)) + } + + @Unroll + def "parseValue throws exception for invalid input #value"() { + when: + new GraphQLLocalTime().getCoercing().parseValue(value) + then: + thrown(CoercingParseValueException) + + where: + value | _ + '' | _ + 'not a time' | _ + new Object() | _ + } + +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..4e0f05a --- /dev/null +++ b/settings.gradle @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Alexey Zhokhov + * + * 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 + * + * http://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. + */ + +/** + * @author Alexey Zhokhov + */ +rootProject.name = projectName + +include ':graphql-java-datetime' +include ':graphql-datetime-autoconfigure' +include ':graphql-datetime-spring-boot-starter'