Full Code of jcrygier/graphql-jpa for AI

master 0aab3d31074d cached
44 files
101.5 KB
24.7k tokens
93 symbols
1 requests
Download .txt
Repository: jcrygier/graphql-jpa
Branch: master
Commit: 0aab3d31074d
Files: 44
Total size: 101.5 KB

Directory structure:
gitextract_gdex4ibc/

├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── bintray.json
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src/
    ├── main/
    │   └── java/
    │       └── org/
    │           └── crygier/
    │               └── graphql/
    │                   ├── AttributeMapper.java
    │                   ├── ExtendedJpaDataFetcher.java
    │                   ├── GraphQLExecutor.java
    │                   ├── GraphQLSchemaBuilder.java
    │                   ├── IdentityCoercing.java
    │                   ├── JavaScalars.java
    │                   ├── JpaDataFetcher.java
    │                   └── annotation/
    │                       ├── GraphQLIgnore.java
    │                       └── SchemaDocumentation.java
    └── test/
        ├── groovy/
        │   └── org/
        │       └── crygier/
        │           └── graphql/
        │               ├── EmbeddedQueryExecutorTest.groovy
        │               ├── EmbeddedSchemaBuildTest.groovy
        │               ├── GraphQlController.groovy
        │               ├── JavaScalarsTest.groovy
        │               ├── MutableQueryExecutorTest.groovy
        │               ├── MutableSchemaBuildTest.groovy
        │               ├── StarwarsQueryExecutorTest.groovy
        │               ├── StarwarsSchemaBuildTest.groovy
        │               ├── TestApplication.groovy
        │               ├── ThingQueryExecutorTest.groovy
        │               └── model/
        │                   ├── collections/
        │                   │   └── CollectionTest.java
        │                   ├── embeddings/
        │                   │   ├── EmbeddingId.java
        │                   │   └── EmbeddingTest.java
        │                   ├── starwars/
        │                   │   ├── Character.groovy
        │                   │   ├── CodeList.groovy
        │                   │   ├── Droid.groovy
        │                   │   ├── Episode.java
        │                   │   ├── Human.groovy
        │                   │   └── Spaceship.groovy
        │                   ├── users/
        │                   │   ├── DateAndUser.groovy
        │                   │   └── User.groovy
        │                   └── uuid/
        │                       └── Thing.groovy
        └── resources/
            ├── application.yaml
            ├── data.sql
            └── static/
                └── index.html

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.gradle/
.idea/
bin/
build/
*.iml
.classpath
.project
.settings/
classes/
out/


================================================
FILE: .travis.yml
================================================
language: java
jdk:
  - oraclejdk8
deploy:
  provider: bintray
  file: bintray.json
  user: jcrygier
  key:
    secure: obNe/VH/vvGr3nSpUQW7+E0XfQAA8zvkuFOM86AfRs51pxblIgLnBkGua9iuRZ8iV6s/275j/SgVV4vkoq1Bkt1ndnmEcsn0XbRuRhJH7yxDdIIclLP/kCAgRFh08ADKD2k51HsqCIjiiSs+B8V0QFQx9pcMtRMchqq/63H1I/TGHUHEpVLh/2+HkTkqFe/0LavxPi1jMt5qkqsPzyCwvE7oM5rzqKUmAbCh66yhi1ao0DkwJybtIq0yjgfKHVKydAr2O0So8kYRkRnddBxi1NkTrbcXm9kwcrM+bmS4S7eMgRWiq/oNYBD0sefYP5NySsDh+phzjIqGFxvTQvp/EfzKlupR2mogK3GjHmuyl0tII4qjrxEnlT6Pj08UvUb2jloHvckdqpj0Gz8f3Iq3/HsxVRXBMshm11dEFXqHIs6UbGQFtf5TkgP88iPt3kfh+0yAWh5EVp+YAG6HnkrTure2YC0JgiRmYHFD0lYxFQ0LoGteECNg1NpMu1lU/f0EaEy98XX+aCjW5KPSyWNEpTXo74IZsjIZEqN1mbfxvtyKc1p1ANK1oQW23FeAI0ZjnCT8FEntk1UJIZqazw2QQvCyYVawESgqFCzkpN4D6uJjU15xQKQos7tK9f1Lm6Xl47PcaA82iFYFxQji3VdC1a+vlCXWPP+XKua2OPhuAoQ=


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2017 John Crygier and Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
GraphQL for JPA
===============

If you're already using JPA, then you already have a schema defined...don't define it again just for GraphQL!

This is a simple project to extend [graphql-java](https://github.com/andimarek/graphql-java) and have it derive the
schema from a JPA model.  It also implements an execution platform to generate and run JPA queries based on
GraphQL queries.

While limited, there is a lot of power bundled within.  This project takes a somewhat opinionated view of GraphQL, by
introducing things like Pagination, Aggregations, and Sorting.

This project is intended on depending on very little: graphql-java, and some javax annotation packages.  The tests depend
on Spring (with Hibernate for JPA), and Spock for testing.  These tests are a good illustration of how this library might
be used, but any stack (with JPA) should be able to be utilized.

Schema Generation
-----------------

Using a JPA Entity Manager, the models are introspected, and a GraphQL Schema is built.  With this GraphQL schema,
graphql-java does most of the work, except for querying.

Schema Documentation
--------------------

A major part of GraphQL is the ability to have a well documented schema.  This project takes advantage of this, and produces
descriptions for each Entity in the schema.  For the built in types (e.g. PaginationObject) these are rather hard-coded
without much control from the end user.

However, for each Entity / Member that is in your JPA schema, you can document what it's for.  These descriptions are controlled
by the `@SchemaDocumentation` attribute on either a class level, or a field level of your model.

These descriptions will show up in the GraphiQL browser automatically, and generally helps when providing an API to your
end-users.  See the GraphiQL section below for more details.

Pagination
----------

GraphQL does not specify any language or idioms for performing Pagination.  Therefore, this library takes an opinionated
view, similar to that of Spring.

Each model (say Human or Droid - see tests) will have two representations in the generated schema:

- One that models the Entities directly (Human or Droid)
- One that wraps the Entity in a page request (HumanConnection or DroidConnection)

This allows you to query for the "Page" version of any Entity, and return metadata (like total count) alongside of the
actual requested data.  For example:

    {
        HumanConnection(paginationRequest: { page: 1, size: 2 }) {
            totalPages
            totalElements
            content {
                name
            }
        }
    }

Will return:

    {
        HumanConnection: {
            totalPages: 3,
            totalElements: 5,
            content: [
                { name: 'Luke Skywalker' },
                { name: 'Darth Vader' }
            ]
        }
    }

Of course, an extra query is needed to get the total elements, so if you have not requested 'totalPages' or 'totalElements'
this query will not be executed.

NOTE: The "Connection" name is used here for further extension (Aggregations, etc...).  The name is borrowed
from suggestions by Facebook developers: https://github.com/facebook/graphql/issues/4

Aggregations
------------

Not yet implemented, but will be similar to Pagination

Sorting
-------

Sorting is supported on any field.  Simply pass in an 'orderBy' argument with the value of ASC or DESC.  Here's an example
of sorting by name for Human objects:

    {
        Human {
            name(orderBy: DESC)
            homePlanet
        }
    }

Query Injectors
---------------

Not yet implemented.  Main use case would be to intercept query execution for security purposes.

GraphiQL
--------

GraphiQL (https://github.com/graphql/graphiql) has been introduced for simple testing (in the test package, as I don't
want to assume your web stack).  Simply launch TestApplication as a Java Application, and navigate to http://localhost:8080/
to launch.  You will notice a 'Docs' button at the upper right, that when expanded will show you the running schema (Star
Wars in this demo).

You can enter GraphQL queries in the left pannel, and hit the run button, and the results should come back in the right
panel.  If your query has variables, there is a minimized panel at the bottom left.  Simply click on this to expand, and
type in your variables as a JSON string (don't forget to quote the keys!).  Enjoy!

================================================
FILE: bintray.json
================================================
{
    "package": {
        "name": "GraphQL-JPA",
        "repo": "maven",
        "subject": "jcrygier"
    },
    "version": {
        "name": "0.6"
    },
    "files": [
        {"includePattern": "build/libs/(.*)", "excludePattern": ".*/do-not-deploy/.*", "uploadPattern": "com/crygier/graphql-jpa/0.6/$1"}
    ],
    "publish": true
}


================================================
FILE: build.gradle
================================================
apply plugin: 'groovy'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'maven'
apply plugin: 'maven-publish'

group = 'com.crygier'
version = '0.6'

jar {
    baseName = 'graphql-jpa'
    version = project.version
}
sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
    maven {
        url  "http://dl.bintray.com/andimarek/graphql-java"
    }
}

configurations {
    provided
    compile.extendsFrom provided
}

dependencies {
    compile 'com.graphql-java:graphql-java:4.2'
    compile 'javax.transaction:javax.transaction-api:1.2'
    provided 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'

    testCompile "org.springframework.boot:spring-boot-starter:1.5.1.RELEASE"
    testCompile "org.springframework.boot:spring-boot-starter-test:1.5.1.RELEASE"
    testCompile "org.springframework.boot:spring-boot-starter-data-jpa:1.5.1.RELEASE"
    testCompile "org.springframework.boot:spring-boot-starter-web:1.5.1.RELEASE"
    testCompile 'junit:junit:4.11'
    testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
    testCompile 'org.spockframework:spock-spring:1.0-groovy-2.4'
    testCompile 'org.codehaus.groovy:groovy-all:2.4.4'
    testCompile 'cglib:cglib-nodep:3.1'
    testCompile 'org.objenesis:objenesis:2.1'

    testRuntime "com.h2database:h2:1.4.190"
    //testRuntime 'org.hibernate:hibernate-validator:4.3.0.Final'
}

publishing {
	publications {
		MyPublication(MavenPublication) {
			from components.java
			groupId 'com.crygier'
    		artifactId 'graphql-jpa'
    		version project.version
            artifact sourcesJar
		}
	}
}

model {
    tasks.generatePomFileForMyPublicationPublication {
        destination = file("$buildDir/libs/${project.name}-${version}.pom")
    }

	tasks.assemble {
		dependsOn tasks.generatePomFileForMyPublicationPublication
	}
}

task sourcesJar(type: Jar, dependsOn: classes) {
    classifier = 'sources'
    from sourceSets.main.allSource
}

artifacts {
    archives sourcesJar
}

eclipse {
    classpath {
         containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
         containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.3'
}


================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Tue Sep 15 19:06:52 CDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.3-bin.zip


================================================
FILE: gradlew
================================================
#!/usr/bin/env bash

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# 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
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
esac

# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi

# 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\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-

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" ] ; 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"`

    # 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

# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
    JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"


================================================
FILE: gradlew.bat
================================================
@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

@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=

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@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 Windowz variants

if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_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=%*
goto execute

:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
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


================================================
FILE: src/main/java/org/crygier/graphql/AttributeMapper.java
================================================
package org.crygier.graphql;

import graphql.schema.GraphQLType;

import java.util.Optional;

/**
 * (Functional) Interface to map Classes to GraphQLTypes.
 */
@FunctionalInterface
public interface AttributeMapper {

    /**
     * Returns the GraphQLType for the given Class.  If this mapper doesn't know how to handle this particular class,
     * it MUST return an empty Optional.
     *
     * @param javaType
     * @return
     */
    Optional<GraphQLType> getBasicAttributeType(Class javaType);

}


================================================
FILE: src/main/java/org/crygier/graphql/ExtendedJpaDataFetcher.java
================================================
package org.crygier.graphql;

import graphql.language.Argument;
import graphql.language.Field;
import graphql.language.IntValue;
import graphql.language.ObjectValue;
import graphql.schema.DataFetchingEnvironment;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.SingularAttribute;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

public class ExtendedJpaDataFetcher extends JpaDataFetcher {

    public ExtendedJpaDataFetcher(EntityManager entityManager, EntityType<?> entityType) {
        super(entityManager, entityType);
    }

    @Override
    public Object get(DataFetchingEnvironment environment) {
        Field field = environment.getFields().iterator().next();
        Map<String, Object> result = new LinkedHashMap<>();

        PageInformation pageInformation = extractPageInformation(environment, field);

        // See which fields we're requesting
        Optional<Field> totalPagesSelection = getSelectionField(field, "totalPages");
        Optional<Field> totalElementsSelection = getSelectionField(field, "totalElements");
        Optional<Field> contentSelection = getSelectionField(field, "content");

        if (contentSelection.isPresent())
            result.put("content", getQuery(environment, contentSelection.get()).setMaxResults(pageInformation.size).setFirstResult((pageInformation.page - 1) * pageInformation.size).getResultList());

        if (totalElementsSelection.isPresent() || totalPagesSelection.isPresent()) {
            final Long totalElements = contentSelection
                    .map(contentField -> getCountQuery(environment, contentField).getSingleResult())
                    // if no "content" was selected an empty Field can be used
                    .orElseGet(() -> getCountQuery(environment, new Field()).getSingleResult());

            result.put("totalElements", totalElements);
            result.put("totalPages", ((Double) Math.ceil(totalElements / (double) pageInformation.size)).longValue());
        }

        return result;
    }

    private TypedQuery<Long> getCountQuery(DataFetchingEnvironment environment, Field field) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Long> query = cb.createQuery(Long.class);
        Root root = query.from(entityType);

        SingularAttribute idAttribute = entityType.getId(Object.class);
        query.select(cb.count(root.get(idAttribute.getName())));
        List<Predicate> predicates = field.getArguments().stream().map(it -> cb.equal(root.get(it.getName()), convertValue(environment, it, it.getValue()))).collect(Collectors.toList());
        query.where(predicates.toArray(new Predicate[predicates.size()]));

        return entityManager.createQuery(query);
    }

    private Optional<Field> getSelectionField(Field field, String fieldName) {
        return field.getSelectionSet().getSelections().stream().filter(it -> it instanceof Field).map(it -> (Field) it).filter(it -> fieldName.equals(it.getName())).findFirst();
    }

    private PageInformation extractPageInformation(DataFetchingEnvironment environment, Field field) {
        Optional<Argument> paginationRequest = field.getArguments().stream().filter(it -> GraphQLSchemaBuilder.PAGINATION_REQUEST_PARAM_NAME.equals(it.getName())).findFirst();
        if (paginationRequest.isPresent()) {
            field.getArguments().remove(paginationRequest.get());

            ObjectValue paginationValues = (ObjectValue) paginationRequest.get().getValue();
            IntValue page = (IntValue) paginationValues.getObjectFields().stream().filter(it -> "page".equals(it.getName())).findFirst().get().getValue();
            IntValue size = (IntValue) paginationValues.getObjectFields().stream().filter(it -> "size".equals(it.getName())).findFirst().get().getValue();

            return new PageInformation(page.getValue().intValue(), size.getValue().intValue());
        }

        return new PageInformation(1, Integer.MAX_VALUE);
    }

    private static final class PageInformation {
        public Integer page;
        public Integer size;

        public PageInformation(Integer page, Integer size) {
            this.page = page;
            this.size = size;
        }
    }


}


================================================
FILE: src/main/java/org/crygier/graphql/GraphQLExecutor.java
================================================
package org.crygier.graphql;

import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.util.Collection;
import java.util.Map;

/**
 * A GraphQL executor capable of constructing a {@link GraphQLSchema} from a JPA {@link EntityManager}. The executor
 * uses the constructed schema to execute queries directly from the JPA data source.
 * <p>
 * If the executor is given a mutator function, it is feasible to manipulate the {@link GraphQLSchema}, introducing
 * the option to add mutations, subscriptions etc.
 */
public class GraphQLExecutor {

    @Resource
    private EntityManager entityManager;
    private GraphQL graphQL;
    private GraphQLSchema graphQLSchema;
    private GraphQLSchema.Builder builder;

    protected GraphQLExecutor() {
        createGraphQL(null);
    }

    /**
     * Creates a read-only GraphQLExecutor using the entities discovered from the given {@link EntityManager}.
     *
     * @param entityManager The entity manager from which the JPA classes annotated with
     *                      {@link javax.persistence.Entity} is extracted as {@link GraphQLSchema} objects.
     */
    public GraphQLExecutor(EntityManager entityManager) {
        this.entityManager = entityManager;
        createGraphQL(null);
    }

    /**
     * Creates a read-only GraphQLExecutor using the entities discovered from the given {@link EntityManager}.
     *
     * @param entityManager The entity manager from which the JPA classes annotated with
     *                      {@link javax.persistence.Entity} is extracted as {@link GraphQLSchema} objects.
     * @param attributeMappers Custom {@link AttributeMapper} list, if you need any non-standard mappings.
     */
    public GraphQLExecutor(EntityManager entityManager, Collection<AttributeMapper> attributeMappers) {
        this.entityManager = entityManager;
        createGraphQL(attributeMappers);
    }

    @PostConstruct
    protected synchronized void createGraphQL() {
        createGraphQL(null);
    }

    protected synchronized void createGraphQL(Collection<AttributeMapper> attributeMappers) {
        if (entityManager != null) {
            if (builder == null && attributeMappers == null) {
                this.builder = new GraphQLSchemaBuilder(entityManager);
            } else if (builder == null) {
                this.builder = new GraphQLSchemaBuilder(entityManager, attributeMappers);
            }
            this.graphQLSchema = builder.build();
            this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
        }
    }

    /**
     * @return The {@link GraphQLSchema} used by this executor.
     */
    public GraphQLSchema getGraphQLSchema() {
        return graphQLSchema;
    }

    @Transactional
    public ExecutionResult execute(String query) {
        return graphQL.execute(query);
    }

    @Transactional
    public ExecutionResult execute(String query, Map<String, Object> arguments) {
        if (arguments == null)
            return graphQL.execute(query);
        return graphQL.execute(ExecutionInput.newExecutionInput().query(query).variables(arguments).build());
    }

    /**
     * Gets the builder that was used to create the Schema that this executor is basing its query executions on. The
     * builder can be used to update the executor with the {@link #updateSchema(GraphQLSchema.Builder)} method.
     * @return An instance of a builder.
     */
    public GraphQLSchema.Builder getBuilder() {
        return builder;
    }

    /**
     * Returns the schema that this executor bases its queries on.
     * @return An instance of a {@link GraphQLSchema}.
     */
    public GraphQLSchema getSchema() {
        return graphQLSchema;
    }

    /**
     * Uses the given builder to re-create and replace the {@link GraphQLSchema}
     * that this executor uses to execute its queries.
     *
     * @param builder The builder to recreate the current {@link GraphQLSchema} and {@link GraphQL} instances.
     * @return The same executor but with a new {@link GraphQL} schema.
     */
    public GraphQLExecutor updateSchema(GraphQLSchema.Builder builder) {
        this.builder = builder;
        createGraphQL(null);
        return this;
    }

    /**
     * Uses the given builder to re-create and replace the {@link GraphQLSchema}
     * that this executor uses to execute its queries.
     *
     * @param builder The builder to recreate the current {@link GraphQLSchema} and {@link GraphQL} instances.
     * @param attributeMappers Custom {@link AttributeMapper} list, if you need any non-standard mappings.
     * @return The same executor but with a new {@link GraphQL} schema.
     */
    public GraphQLExecutor updateSchema(GraphQLSchema.Builder builder, Collection<AttributeMapper> attributeMappers) {
        this.builder = builder;
        createGraphQL(attributeMappers);
        return this;
    }

}


================================================
FILE: src/main/java/org/crygier/graphql/GraphQLSchemaBuilder.java
================================================
package org.crygier.graphql;

import graphql.Scalars;
import graphql.schema.GraphQLArgument;
import graphql.schema.GraphQLEnumType;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLInputObjectField;
import graphql.schema.GraphQLInputObjectType;
import graphql.schema.GraphQLInputType;
import graphql.schema.GraphQLList;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLOutputType;
import graphql.schema.GraphQLScalarType;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLType;
import graphql.schema.GraphQLTypeReference;
import org.crygier.graphql.annotation.GraphQLIgnore;
import org.crygier.graphql.annotation.SchemaDocumentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.EntityManager;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.Type;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * A wrapper for the {@link GraphQLSchema.Builder}. In addition to exposing the traditional builder functionality,
 * this class constructs an initial {@link GraphQLSchema} by scanning the given {@link EntityManager} for relevant
 * JPA entities. This happens at construction time.
 *
 * Note: This class should not be accessed outside this library.
 */
public class GraphQLSchemaBuilder extends GraphQLSchema.Builder {

    public static final String PAGINATION_REQUEST_PARAM_NAME = "paginationRequest";
    private static final Logger log = LoggerFactory.getLogger(GraphQLSchemaBuilder.class);

    private final EntityManager entityManager;
    private final Map<Class, GraphQLType> classCache = new HashMap<>();
    private final Map<EmbeddableType<?>, GraphQLObjectType> embeddableCache = new HashMap<>();
    private final Map<EntityType, GraphQLObjectType> entityCache = new HashMap<>();
    private final List<AttributeMapper> attributeMappers = new ArrayList<>();

    /**
     * Initialises the builder with the given {@link EntityManager} from which we immediately start to scan for
     * entities to include in the GraphQL schema.
     * @param entityManager The manager containing the data models to include in the final GraphQL schema.
     */
    public GraphQLSchemaBuilder(EntityManager entityManager) {
        this.entityManager = entityManager;

        populateStandardAttributeMappers();

        super.query(getQueryType());
    }

    public GraphQLSchemaBuilder(EntityManager entityManager, Collection<AttributeMapper> attributeMappers) {
        this.entityManager = entityManager;

        this.attributeMappers.addAll(attributeMappers);
        populateStandardAttributeMappers();

        super.query(getQueryType());
    }

    private void populateStandardAttributeMappers() {
        attributeMappers.add(createStandardAttributeMapper(UUID.class, JavaScalars.GraphQLUUID));
        attributeMappers.add(createStandardAttributeMapper(Date.class, JavaScalars.GraphQLDate));
        attributeMappers.add(createStandardAttributeMapper(LocalDateTime.class, JavaScalars.GraphQLLocalDateTime));
        attributeMappers.add(createStandardAttributeMapper(Instant.class, JavaScalars.GraphQLInstant));
        attributeMappers.add(createStandardAttributeMapper(LocalDate.class, JavaScalars.GraphQLLocalDate));
    }

    private AttributeMapper createStandardAttributeMapper(final Class<?> assignableClass, final GraphQLType type) {
        return (javaType) -> {
            if (assignableClass.isAssignableFrom(javaType))
                return Optional.of(type);

            return Optional.empty();
        };
    }

    /**
     * @deprecated Use {@link #build()} instead.
     * @return A freshly built {@link GraphQLSchema}
     */
    @Deprecated()
    public GraphQLSchema getGraphQLSchema() {
        return super.build();
    }

    GraphQLObjectType getQueryType() {
        GraphQLObjectType.Builder queryType = GraphQLObjectType.newObject().name("QueryType_JPA").description("All encompassing schema for this JPA environment");
        queryType.fields(entityManager.getMetamodel().getEntities().stream().filter(this::isNotIgnored).map(this::getQueryFieldDefinition).collect(Collectors.toList()));
        queryType.fields(entityManager.getMetamodel().getEntities().stream().filter(this::isNotIgnored).map(this::getQueryFieldPageableDefinition).collect(Collectors.toList()));
        queryType.fields(entityManager.getMetamodel().getEmbeddables().stream().filter(this::isNotIgnored).map(this::getQueryEmbeddedFieldDefinition).collect(Collectors.toList()));

        return queryType.build();
    }

    GraphQLFieldDefinition getQueryFieldDefinition(EntityType<?> entityType) {
        return GraphQLFieldDefinition.newFieldDefinition()
                .name(entityType.getName())
                .description(getSchemaDocumentation(entityType.getJavaType()))
                .type(new GraphQLList(getObjectType(entityType)))
                .dataFetcher(new JpaDataFetcher(entityManager, entityType))
                .argument(entityType.getAttributes().stream().filter(this::isValidInput).filter(this::isNotIgnored).flatMap(this::getArgument).collect(Collectors.toList()))
                .build();
    }
    
    GraphQLFieldDefinition getQueryEmbeddedFieldDefinition(EmbeddableType<?> embeddableType) {
    	String embeddedName = embeddableType.getJavaType().getSimpleName();
        return GraphQLFieldDefinition.newFieldDefinition()
                .name(embeddedName)
                .description(getSchemaDocumentation(embeddableType.getJavaType()))
                .type(new GraphQLList(getObjectType(embeddableType)))
                .argument(embeddableType.getAttributes().stream().filter(this::isValidInput).filter(this::isNotIgnored).flatMap(this::getArgument).collect(Collectors.toList()))
                .build();
    }

    private GraphQLFieldDefinition getQueryFieldPageableDefinition(EntityType<?> entityType) {
        GraphQLObjectType pageType = GraphQLObjectType.newObject()
                .name(entityType.getName() + "Connection")
                .description("'Connection' response wrapper object for " + entityType.getName() + ".  When pagination or aggregation is requested, this object will be returned with metadata about the query.")
                .field(GraphQLFieldDefinition.newFieldDefinition().name("totalPages").description("Total number of pages calculated on the database for this pageSize.").type(Scalars.GraphQLLong).build())
                .field(GraphQLFieldDefinition.newFieldDefinition().name("totalElements").description("Total number of results on the database for this query.").type(Scalars.GraphQLLong).build())
                .field(GraphQLFieldDefinition.newFieldDefinition().name("content").description("The actual object results").type(new GraphQLList(getObjectType(entityType))).build())
                .build();

        return GraphQLFieldDefinition.newFieldDefinition()
                .name(entityType.getName() + "Connection")
                .description("'Connection' request wrapper object for " + entityType.getName() + ".  Use this object in a query to request things like pagination or aggregation in an argument.  Use the 'content' field to request actual fields ")
                .type(pageType)
                .dataFetcher(new ExtendedJpaDataFetcher(entityManager, entityType))
                .argument(paginationArgument)
                .build();
    }

    private Stream<GraphQLArgument> getArgument(Attribute attribute) {
        return getAttributeType(attribute)
                .filter(type -> type instanceof GraphQLInputType)
                .filter(type -> attribute.getPersistentAttributeType() != Attribute.PersistentAttributeType.EMBEDDED ||
                        (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED && type instanceof GraphQLScalarType))
                .map(type -> {
                    String name = attribute.getName();                   

                    return GraphQLArgument.newArgument()
                            .name(name)
                            .type((GraphQLInputType) type)
                            .build();
                });
    }

    GraphQLObjectType getObjectType(EntityType<?> entityType) {
        if (entityCache.containsKey(entityType))
            return entityCache.get(entityType);

        GraphQLObjectType answer = GraphQLObjectType.newObject()
                .name(entityType.getName())
                .description(getSchemaDocumentation(entityType.getJavaType()))
                .fields(entityType.getAttributes().stream().filter(this::isNotIgnored).flatMap(this::getObjectField).collect(Collectors.toList()))
                .build();

        entityCache.put(entityType, answer);

        return answer;
    }
    
    GraphQLObjectType getObjectType(EmbeddableType<?> embeddableType) {
    	
        if (embeddableCache.containsKey(embeddableType))
            return embeddableCache.get(embeddableType);

        String embeddableName= embeddableType.getJavaType().getSimpleName();
        GraphQLObjectType answer = GraphQLObjectType.newObject()
                .name(embeddableName)
                .description(getSchemaDocumentation(embeddableType.getJavaType()))
                .fields(embeddableType.getAttributes().stream().filter(this::isNotIgnored).flatMap(this::getObjectField).collect(Collectors.toList()))
                .build();

        embeddableCache.put(embeddableType, answer);

        return answer;
    }

    private Stream<GraphQLFieldDefinition> getObjectField(Attribute attribute) {
        return getAttributeType(attribute)
                .filter(type -> type instanceof GraphQLOutputType)
                .map(type -> {
                    List<GraphQLArgument> arguments = new ArrayList<>();
                    arguments.add(GraphQLArgument.newArgument().name("orderBy").type(orderByDirectionEnum).build());            // Always add the orderBy argument

                    // Get the fields that can be queried on (i.e. Simple Types, no Sub-Objects)
                    if (attribute instanceof SingularAttribute
                            && attribute.getPersistentAttributeType() != Attribute.PersistentAttributeType.BASIC) {
                        ManagedType foreignType = (ManagedType) ((SingularAttribute) attribute).getType();

                        Stream<Attribute> attributes = findBasicAttributes(foreignType.getAttributes());

                        attributes.forEach(it -> {
                            arguments.add(GraphQLArgument.newArgument()
                                    .name(it.getName())
                                    .type((GraphQLInputType) getAttributeType(it).findFirst().get())
                                    .build());
                        });
                    }

                    String name = attribute.getName();
                    

                    return GraphQLFieldDefinition.newFieldDefinition()
                            .name(name)
                            .description(getSchemaDocumentation(attribute.getJavaMember()))
                            .type((GraphQLOutputType) type)
                            .argument(arguments)
                            .build();
                });
    }

    private Stream<Attribute> findBasicAttributes(Collection<Attribute> attributes) {
        return attributes.stream().filter(this::isNotIgnored).filter(it -> it.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC);
    }

    private GraphQLType getBasicAttributeType(Class javaType) {
        // First check our 'standard' and 'customized' Attribute Mappers.  Use them if possible
        Optional<AttributeMapper> customMapper = attributeMappers.stream()
                .filter(it -> it.getBasicAttributeType(javaType).isPresent())
                .findFirst();

        if (customMapper.isPresent())
            return customMapper.get().getBasicAttributeType(javaType).get();
        else if (String.class.isAssignableFrom(javaType))
            return Scalars.GraphQLString;
        else if (Integer.class.isAssignableFrom(javaType) || int.class.isAssignableFrom(javaType))
            return Scalars.GraphQLInt;
        else if (Short.class.isAssignableFrom(javaType) || short.class.isAssignableFrom(javaType))
            return Scalars.GraphQLShort;
        else if (Float.class.isAssignableFrom(javaType) || float.class.isAssignableFrom(javaType)
                || Double.class.isAssignableFrom(javaType) || double.class.isAssignableFrom(javaType))
            return Scalars.GraphQLFloat;
        else if (Long.class.isAssignableFrom(javaType) || long.class.isAssignableFrom(javaType))
            return Scalars.GraphQLLong;
        else if (Boolean.class.isAssignableFrom(javaType) || boolean.class.isAssignableFrom(javaType))
            return Scalars.GraphQLBoolean;
        else if (javaType.isEnum()) {
            return getTypeFromJavaType(javaType);
        } else if (BigDecimal.class.isAssignableFrom(javaType)) {
            return Scalars.GraphQLBigDecimal;
        }

        throw new UnsupportedOperationException(
                "Class could not be mapped to GraphQL: '" + javaType.getClass().getTypeName() + "'");
    }

    private Stream<GraphQLType> getAttributeType(Attribute attribute) {
        if (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC) {
            try {
                return Stream.of(getBasicAttributeType(attribute.getJavaType()));
            } catch (UnsupportedOperationException e) {
                //fall through to the exception below
                //which is more useful because it also contains the declaring member
            }
        } else if (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ONE_TO_MANY || attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.MANY_TO_MANY) {
            EntityType foreignType = (EntityType) ((PluralAttribute) attribute).getElementType();
            return Stream.of(new GraphQLList(new GraphQLTypeReference(foreignType.getName())));
        } else if (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.MANY_TO_ONE || attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ONE_TO_ONE) {
            EntityType foreignType = (EntityType) ((SingularAttribute) attribute).getType();
            return Stream.of(new GraphQLTypeReference(foreignType.getName()));
        } else if (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ELEMENT_COLLECTION) {
            Type foreignType = ((PluralAttribute) attribute).getElementType();
            return Stream.of(new GraphQLList(getTypeFromJavaType(foreignType.getJavaType())));
        } else if (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED) {
            EmbeddableType<?> embeddableType = (EmbeddableType<?>) ((SingularAttribute<?,?>) attribute).getType();
            return Stream.of(new GraphQLTypeReference(embeddableType.getJavaType().getSimpleName()));
        }

        final String declaringType = attribute.getDeclaringType().getJavaType().getName(); // fully qualified name of the entity class
        final String declaringMember = attribute.getJavaMember().getName(); // field name in the entity class

        throw new UnsupportedOperationException(
                "Attribute could not be mapped to GraphQL: field '" + declaringMember + "' of entity class '" + declaringType + "'");
    }

    private boolean isValidInput(Attribute attribute) {
        return attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC ||
                attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ELEMENT_COLLECTION ||
                attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED;
    }

    private String getSchemaDocumentation(Member member) {
        if (member instanceof AnnotatedElement) {
            return getSchemaDocumentation((AnnotatedElement) member);
        }

        return null;
    }

    private String getSchemaDocumentation(AnnotatedElement annotatedElement) {
        if (annotatedElement != null) {
            SchemaDocumentation schemaDocumentation = annotatedElement.getAnnotation(SchemaDocumentation.class);
            return schemaDocumentation != null ? schemaDocumentation.value() : null;
        }

        return null;
    }

    private boolean isNotIgnored(Attribute attribute) {
        return isNotIgnored(attribute.getJavaMember()) && isNotIgnored(attribute.getJavaType());
    }
    
    private boolean isNotIgnored(EmbeddableType<?> embeddableType) {
        return isNotIgnored(embeddableType.getJavaType());
    }

    private boolean isNotIgnored(EntityType entityType) {
        return isNotIgnored(entityType.getJavaType());
    }

    private boolean isNotIgnored(Member member) {
        return member instanceof AnnotatedElement && isNotIgnored((AnnotatedElement) member);
    }

    private boolean isNotIgnored(AnnotatedElement annotatedElement) {
        if (annotatedElement != null) {
            GraphQLIgnore schemaDocumentation = annotatedElement.getAnnotation(GraphQLIgnore.class);
            return schemaDocumentation == null;
        }

        return false;
    }

    private GraphQLType getTypeFromJavaType(Class clazz) {
        if (clazz.isEnum()) {
            if (classCache.containsKey(clazz))
                return classCache.get(clazz);

            GraphQLEnumType.Builder enumBuilder = GraphQLEnumType.newEnum().name(clazz.getSimpleName());
            int ordinal = 0;
            for (Enum enumValue : ((Class<Enum>) clazz).getEnumConstants())
                enumBuilder.value(enumValue.name(), ordinal++);

            GraphQLType answer = enumBuilder.build();
            setIdentityCoercing(answer);

            classCache.put(clazz, answer);

            return answer;
        }

        return getBasicAttributeType(clazz);
    }

    /**
     * A bit of a hack, since JPA will deserialize our Enum's for us...we don't want GraphQL doing it.
     *
     * @param type
     */
    private void setIdentityCoercing(GraphQLType type) {
        try {
            Field coercing = type.getClass().getDeclaredField("coercing");
            coercing.setAccessible(true);
            coercing.set(type, new IdentityCoercing());
        } catch (Exception e) {
            log.error("Unable to set coercing for " + type, e);
        }
    }

    private static final GraphQLArgument paginationArgument =
            GraphQLArgument.newArgument()
                    .name(PAGINATION_REQUEST_PARAM_NAME)
                    .type(GraphQLInputObjectType.newInputObject()
                            .name("PaginationObject")
                            .description("Query object for Pagination Requests, specifying the requested page, and that page's size.\n\nNOTE: 'page' parameter is 1-indexed, NOT 0-indexed.\n\nExample: paginationRequest { page: 1, size: 20 }")
                            .field(GraphQLInputObjectField.newInputObjectField().name("page").description("Which page should be returned, starting with 1 (1-indexed)").type(Scalars.GraphQLInt).build())
                            .field(GraphQLInputObjectField.newInputObjectField().name("size").description("How many results should this page contain").type(Scalars.GraphQLInt).build())
                            .build()
                    ).build();

    private static final GraphQLEnumType orderByDirectionEnum =
            GraphQLEnumType.newEnum()
                    .name("OrderByDirection")
                    .description("Describes the direction (Ascending / Descending) to sort a field.")
                    .value("ASC", 0, "Ascending")
                    .value("DESC", 1, "Descending")
                    .build();


}


================================================
FILE: src/main/java/org/crygier/graphql/IdentityCoercing.java
================================================
package org.crygier.graphql;

import graphql.schema.Coercing;

public class IdentityCoercing implements Coercing{

    @Override
    public Object serialize(Object input) {
        return input;
    }

    @Override
    public Object parseValue(Object input) {
        return input;
    }

    @Override
    public Object parseLiteral(Object input) {
        return input;
    }

}


================================================
FILE: src/main/java/org/crygier/graphql/JavaScalars.java
================================================
package org.crygier.graphql;

import graphql.language.IntValue;
import graphql.language.StringValue;
import graphql.schema.Coercing;
import graphql.schema.CoercingSerializeException;
import graphql.schema.GraphQLScalarType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigInteger;
import java.text.DateFormat;
import java.text.ParseException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.TimeZone;
import java.util.UUID;

public class JavaScalars {
    static final Logger log = LoggerFactory.getLogger(JavaScalars.class);

    public static GraphQLScalarType GraphQLLocalDateTime = new GraphQLScalarType("LocalDateTime", "Date type", new Coercing() {
        @Override
        public Object serialize(Object input) {
            if (input instanceof String) {
                return parseStringToLocalDateTime((String) input);
            } else if (input instanceof LocalDateTime) {
                return input;
            } else if (input instanceof Long) {
                return parseLongToLocalDateTime((Long) input);
            } else if (input instanceof Integer) {
                return parseLongToLocalDateTime((Integer) input);
            }
            return null;
        }

        @Override
        public Object parseValue(Object input) {
            return serialize(input);
        }

        @Override
        public Object parseLiteral(Object input) {
            if (input instanceof StringValue) {
                return parseStringToLocalDateTime(((StringValue) input).getValue());
            } else if (input instanceof IntValue) {
                BigInteger value = ((IntValue) input).getValue();
                return parseLongToLocalDateTime(value.longValue());
            }
            return null;
        }

        private LocalDateTime parseLongToLocalDateTime(long input) {
            return LocalDateTime.ofInstant(Instant.ofEpochSecond(input), TimeZone.getDefault().toZoneId());
        }

        private LocalDateTime parseStringToLocalDateTime(String input) {
            try {
                return LocalDateTime.parse(input);
            } catch (DateTimeParseException e) {
                log.warn("Failed to parse Date from input: " + input, e);
                return null;
            }
        }
    });

    public static GraphQLScalarType GraphQLInstant = new GraphQLScalarType("Instant", "Date type", new Coercing<Instant, Long>() {

        @Override
        public Long serialize(Object input) {
            if (input instanceof Instant) {
                return ((Instant) input).getEpochSecond();
            }
            throw new CoercingSerializeException(
                    "Expected type 'Instant' but was '" + input.getClass().getSimpleName() + "'.");
        }

        @Override
        public Instant parseValue(Object input) {
            if (input instanceof Long) {
                return Instant.ofEpochSecond((Long) input);
            } else if (input instanceof Integer) {
                return Instant.ofEpochSecond((Integer) input);
            }
            throw new CoercingSerializeException(
                    "Expected type 'Long' or 'Integer' but was '" + input.getClass().getSimpleName() + "'.");
        }

        @Override
        public Instant parseLiteral(Object input) {
            if (input instanceof IntValue) {
                return Instant.ofEpochSecond(((IntValue) input).getValue().longValue());
            }
            return null;
        }

    });

    public static GraphQLScalarType GraphQLLocalDate = new GraphQLScalarType("LocalDate", "Date type", new Coercing() {
        @Override
        public Object serialize(Object input) {
            if (input instanceof String) {
                return parseStringToLocalDate((String) input);
            } else if (input instanceof LocalDate) {
                return input;
            } else if (input instanceof Long) {
                return parseLongToLocalDate((Long) input);
            } else if (input instanceof Integer) {
                return parseLongToLocalDate((Integer) input);
            }
            return null;
        }

        @Override
        public Object parseValue(Object input) {
            return serialize(input);
        }

        @Override
        public Object parseLiteral(Object input) {
            if (input instanceof StringValue) {
                return parseStringToLocalDate(((StringValue) input).getValue());
            } else if (input instanceof IntValue) {
                BigInteger value = ((IntValue) input).getValue();
                return parseLongToLocalDate(value.longValue());
            }
            return null;
        }

        private LocalDate parseLongToLocalDate(long input) {
            return LocalDateTime.ofInstant(Instant.ofEpochSecond(input), TimeZone.getDefault().toZoneId()).toLocalDate();
        }

        private LocalDate parseStringToLocalDate(String input) {
            try {
                return LocalDate.parse(input);
            } catch (DateTimeParseException e) {
                log.warn("Failed to parse Date from input: " + input, e);
                return null;
            }
        }
    });

    public static GraphQLScalarType GraphQLDate = new GraphQLScalarType("Date", "Date type", new Coercing() {

        @Override
        public Object serialize(Object input) {
            if (input instanceof String) {
                return parseStringToDate((String) input);
            } else if (input instanceof Date) {
                return input;
            } else if (input instanceof Long) {
                return new Date(((Long) input).longValue());
            } else if (input instanceof Integer) {
                return new Date(((Integer) input).longValue());
            }
            return null;
        }

        @Override
        public Object parseValue(Object input) {
            return serialize(input);
        }

        @Override
        public Object parseLiteral(Object input) {
            if (input instanceof StringValue) {
                return parseStringToDate(((StringValue) input).getValue());
            } else if (input instanceof IntValue) {
                BigInteger value = ((IntValue) input).getValue();
                return new Date(value.longValue());
            }
            return null;
        }

        private Date parseStringToDate(String input) {
            try {
                return DateFormat.getInstance().parse(input);
            } catch (ParseException e) {
                log.warn("Failed to parse Date from input: " + input, e);
                return null;
            }
        }
    });

    public static GraphQLScalarType GraphQLUUID = new GraphQLScalarType("UUID", "UUID type", new Coercing() {

        @Override
        public Object serialize(Object input) {
            if (input instanceof UUID) {
                return  input;
            }
            return null;
        }

        @Override
        public Object parseValue(Object input) {
           if (input instanceof String) {
                return parseStringToUUID((String) input);
            }
            return null;
        }

        @Override
        public Object parseLiteral(Object input) {
            if (input instanceof StringValue) {
                return parseStringToUUID(((StringValue) input).getValue());
            }
            return null;
        }

        private UUID parseStringToUUID(String input) {
            try {
                return UUID.fromString(input);
            } catch (IllegalArgumentException e) {
                log.warn("Failed to parse UUID from input: " + input, e);
                return null;
            }
        }
    });
}


================================================
FILE: src/main/java/org/crygier/graphql/JpaDataFetcher.java
================================================
package org.crygier.graphql;

import graphql.language.*;
import graphql.schema.*;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.*;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
import java.util.*;
import java.util.stream.Collectors;

public class JpaDataFetcher implements DataFetcher {

    protected EntityManager entityManager;
    protected EntityType<?> entityType;

    public JpaDataFetcher(EntityManager entityManager, EntityType<?> entityType) {
        this.entityManager = entityManager;
        this.entityType = entityType;
    }

    @Override
    public Object get(DataFetchingEnvironment environment) {
        return getQuery(environment, environment.getFields().iterator().next()).getResultList();
    }

    protected TypedQuery getQuery(DataFetchingEnvironment environment, Field field) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Object> query = cb.createQuery((Class) entityType.getJavaType());
        Root root = query.from(entityType);

        List<Argument> arguments = new ArrayList<>();

        // Loop through all of the fields being requested
        field.getSelectionSet().getSelections().forEach(selection -> {
            if (selection instanceof Field) {
                Field selectedField = (Field) selection;

                // "__typename" is part of the graphql introspection spec and has to be ignored by jpa
                if(!"__typename".equals(selectedField.getName())) {

                    Path fieldPath = root.get(selectedField.getName());

                    // Process the orderBy clause
                    Optional<Argument> orderByArgument = selectedField.getArguments().stream().filter(it -> "orderBy".equals(it.getName())).findFirst();
                    if (orderByArgument.isPresent()) {
                        if ("DESC".equals(((EnumValue) orderByArgument.get().getValue()).getName()))
                            query.orderBy(cb.desc(fieldPath));
                        else
                            query.orderBy(cb.asc(fieldPath));
                    }

                    // Process arguments clauses
                    arguments.addAll(selectedField.getArguments().stream()
                            .filter(it -> !"orderBy".equals(it.getName()))
                            .map(it -> new Argument(selectedField.getName() + "." + it.getName(), it.getValue()))
                            .collect(Collectors.toList()));

                    // Check if it's an object and the foreign side is One.  Then we can eagerly fetch causing an inner join instead of 2 queries
                    if (fieldPath.getModel() instanceof SingularAttribute) {
                        SingularAttribute attribute = (SingularAttribute) fieldPath.getModel();
                        if (!attribute.isOptional() && (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.MANY_TO_ONE || attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ONE_TO_ONE))
                            root.fetch(selectedField.getName());
                    }
                }
            }
        });

        arguments.addAll(field.getArguments());

        List<Predicate> predicates = arguments.stream().map(it -> getPredicate(cb, root, environment, it)).collect(Collectors.toList());
        query.where(predicates.toArray(new Predicate[predicates.size()]));

        return entityManager.createQuery(query.distinct(true));
    }

    private Predicate getPredicate(CriteriaBuilder cb, Root root, DataFetchingEnvironment environment, Argument argument) {
        Path path = null;
        if (!argument.getName().contains(".")) {
            Attribute argumentEntityAttribute = getAttribute(environment, argument);

            // If the argument is a list, let's assume we need to join and do an 'in' clause
            if (argumentEntityAttribute instanceof PluralAttribute) {
                Join join = root.join(argument.getName());
                return join.in(convertValue(environment, argument, argument.getValue()));
            }

            path = root.get(argument.getName());

            return cb.equal(path, convertValue(environment, argument, argument.getValue()));
        } else {
            List<String> parts = Arrays.asList(argument.getName().split("\\."));
            for (String part : parts) {
                if (path == null) {
                    path = root.get(part);
                } else {
                    path = path.get(part);
                }
            }

            return cb.equal(path, convertValue(environment, argument, argument.getValue()));
        }
    }

    protected Object convertValue(DataFetchingEnvironment environment, Argument argument, Value value) {
        if (value instanceof StringValue) {
            Object convertedValue =  environment.getArgument(argument.getName());
            if (convertedValue != null) {
                // Return real parameter for instance UUID even if the Value is a StringValue
                return convertedValue;
            } else {
                // Return provided StringValue
                return ((StringValue) value).getValue();
            }
        }
        else if (value instanceof VariableReference)
            return environment.getArguments().get(((VariableReference) value).getName());
        else if (value instanceof ArrayValue)
            return ((ArrayValue) value).getValues().stream().map((it) -> convertValue(environment, argument, it)).collect(Collectors.toList());
        else if (value instanceof EnumValue) {
            Class enumType = getJavaType(environment, argument);
            return Enum.valueOf(enumType, ((EnumValue) value).getName());
        } else if (value instanceof IntValue) {
            return ((IntValue) value).getValue();
        } else if (value instanceof BooleanValue) {
            return ((BooleanValue) value).isValue();
        } else if (value instanceof FloatValue) {
            return ((FloatValue) value).getValue();
        }

        return value.toString();
    }

    private Class getJavaType(DataFetchingEnvironment environment, Argument argument) {
        Attribute argumentEntityAttribute = getAttribute(environment, argument);

        if (argumentEntityAttribute instanceof PluralAttribute)
            return ((PluralAttribute) argumentEntityAttribute).getElementType().getJavaType();

        return argumentEntityAttribute.getJavaType();
    }

    private Attribute getAttribute(DataFetchingEnvironment environment, Argument argument) {
        GraphQLObjectType objectType = getObjectType(environment, argument);
        EntityType entityType = getEntityType(objectType);

        return entityType.getAttribute(argument.getName());
    }

    private EntityType getEntityType(GraphQLObjectType objectType) {
        return entityManager.getMetamodel().getEntities().stream().filter(it -> it.getName().equals(objectType.getName())).findFirst().get();
    }

    private GraphQLObjectType getObjectType(DataFetchingEnvironment environment, Argument argument) {
        GraphQLType outputType = environment.getFieldType();
        if (outputType instanceof GraphQLList)
            outputType = ((GraphQLList) outputType).getWrappedType();

        if (outputType instanceof GraphQLObjectType)
            return (GraphQLObjectType) outputType;

        return null;
    }
}


================================================
FILE: src/main/java/org/crygier/graphql/annotation/GraphQLIgnore.java
================================================
package org.crygier.graphql.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target( { TYPE, FIELD })
@Retention(RUNTIME)
public @interface GraphQLIgnore {
}


================================================
FILE: src/main/java/org/crygier/graphql/annotation/SchemaDocumentation.java
================================================
package org.crygier.graphql.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target( { TYPE, FIELD })
@Retention(RUNTIME)
public @interface SchemaDocumentation {

    String value();

}


================================================
FILE: src/test/groovy/org/crygier/graphql/EmbeddedQueryExecutorTest.groovy
================================================
package org.crygier.graphql

import javax.persistence.EntityManager

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootContextLoader
import org.springframework.context.annotation.Configuration
import org.springframework.test.context.ContextConfiguration

import spock.lang.Ignore
import spock.lang.Specification

@Configuration
@ContextConfiguration(loader = SpringBootContextLoader, classes = TestApplication)
class EmbeddedQueryExecutorTest extends Specification {

	@Autowired
    private GraphQLExecutor executor;
	
	def 'Query Embedded Values'() {
		given:
		def query = '''
        {
            Spaceship (id: "1000"){
                name, created { user {id}}, modified {date}
            }
        }
        '''
		def expected = [
				Spaceship: [[name: "X-Wing", created:[user:[id:"1000"]], modified:null]]
		]

		when:
		def result = executor.execute(query).data

		then:
		result == expected
	}
}


================================================
FILE: src/test/groovy/org/crygier/graphql/EmbeddedSchemaBuildTest.groovy
================================================
package org.crygier.graphql

import graphql.schema.GraphQLObjectType
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootContextLoader
import org.springframework.context.annotation.Configuration
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification

import javax.persistence.EntityManager
import javax.persistence.metamodel.EntityType
import java.util.stream.Collectors

@Configuration
@ContextConfiguration(loader = SpringBootContextLoader, classes = TestApplication)
class EmbeddedSchemaBuildTest extends Specification {

    @Autowired
    private EntityManager entityManager;

    private GraphQLSchemaBuilder builder;

    void setup() {
        builder = new GraphQLSchemaBuilder(entityManager);
    }

    def 'Correctly read embedded keys'() {
        when:
        def embeddingEntity = entityManager.getMetamodel().getEntities().stream().filter { e -> e.name == "EmbeddingTest"}.findFirst().get()
        def graphQlObject = builder.getObjectType(embeddingEntity)

        then:
        graphQlObject.fieldDefinitions.size() == 1
    }

    def 'Correctly extract embedded basic query fields'() {
        when:
        def embeddingEntity = entityManager.getMetamodel().getEntities().stream().filter { e -> e.name == "EmbeddingTest"}.findFirst().get()
        def graphQlFieldDefinition = builder.getQueryFieldDefinition(embeddingEntity)

        then:
        graphQlFieldDefinition.arguments.size() == 0
    }

    def 'Correctly extract a whole moddel with embeddings'() {
        when:
        def q = builder.getQueryType()

        then:
        true
    }

}


================================================
FILE: src/test/groovy/org/crygier/graphql/GraphQlController.groovy
================================================
package org.crygier.graphql

import com.fasterxml.jackson.databind.ObjectMapper
import graphql.ExecutionResult
import groovy.transform.CompileStatic
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController

@RestController
@CompileStatic
class GraphQlController {

    @Autowired
    private GraphQLExecutor graphQLExecutor;

    @Autowired
    private ObjectMapper objectMapper;

    @RequestMapping(path = '/graphql', method = RequestMethod.POST)
    ExecutionResult graphQl(@RequestBody final GraphQLInputQuery query) {
        Map<String, Object> variables = query.getVariables() ? objectMapper.readValue(query.getVariables(), Map) : null;

        return graphQLExecutor.execute(query.getQuery(), variables);
    }

    public static final class GraphQLInputQuery {
        String query;
        String variables;
    }

}

================================================
FILE: src/test/groovy/org/crygier/graphql/JavaScalarsTest.groovy
================================================
package org.crygier.graphql

import graphql.schema.Coercing
import spock.lang.Specification

import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.Month
import java.time.ZoneId

class JavaScalarsTest extends Specification {

    def 'Long to LocalDateTime'() {
        given:
        Coercing coercing = JavaScalars.GraphQLLocalDateTime.getCoercing()

        LocalDateTime localDateTime = LocalDateTime.of(2017, 02, 02, 12, 30, 15)
        long input = localDateTime.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(localDateTime))

        when:
        def result = coercing.serialize(input)

        then:
        result instanceof LocalDateTime

        result.dayOfMonth == 2
        result.month == Month.FEBRUARY
        result.year == 2017
        result.hour == 12
        result.minute == 30
        result.second == 15
    }

    def 'String to LocalDateTime'() {
        given:
        Coercing coercing = JavaScalars.GraphQLLocalDateTime.getCoercing()
        final String input = "2017-02-02T12:30:15"

        when:
        def result = coercing.serialize(input)

        then:
        result instanceof LocalDateTime

        result.dayOfMonth == 2
        result.month == Month.FEBRUARY
        result.year == 2017
        result.hour == 12
        result.minute == 30
        result.second == 15
    }

    def 'Instant to Long'() {
        given:
        Coercing coercing = JavaScalars.GraphQLInstant.getCoercing()
        final instant = Instant.now()

        when:
        def result = coercing.serialize(instant)

        then:
        result instanceof Long
        result == instant.epochSecond
    }

    def 'Long to LocalDate'() {
        given:
        Coercing coercing = JavaScalars.GraphQLLocalDate.getCoercing()
        LocalDateTime localDateTime = LocalDateTime.of(2017, 02, 02, 0, 0, 0)
        long input = localDateTime.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(localDateTime))

        when:
        def result = coercing.serialize(input)

        then:
        result instanceof LocalDate

        result.dayOfMonth == 2
        result.month == Month.FEBRUARY
        result.year == 2017
    }

    def 'String to LocalDate'() {
        given:
        Coercing coercing = JavaScalars.GraphQLLocalDate.getCoercing()
        final String input = "2017-02-02"

        when:
        def result = coercing.serialize(input)

        then:
        result instanceof LocalDate

        result.dayOfMonth == 2
        result.month == Month.FEBRUARY
        result.year == 2017
    }
}


================================================
FILE: src/test/groovy/org/crygier/graphql/MutableQueryExecutorTest.groovy
================================================
package org.crygier.graphql

import graphql.schema.GraphQLFieldDefinition
import graphql.schema.GraphQLObjectType
import graphql.schema.GraphQLSchema
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootContextLoader
import org.springframework.context.annotation.Configuration
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification

import static graphql.Scalars.GraphQLString

@Configuration
@ContextConfiguration(loader = SpringBootContextLoader, classes = TestApplication)
class MutableQueryExecutorTest extends Specification {

    @Autowired
    private GraphQLExecutor executor;

    private final GraphQLObjectType droidMutation = GraphQLObjectType.newObject()
            .name("CreateDroidMutation")
            .field(GraphQLFieldDefinition.newFieldDefinition()
            .name("name")
            .type(GraphQLString))
            .build()

    def 'Can add a schema mutation'() {
        when:
        GraphQLSchema.Builder builder = executor.getBuilder().mutation(droidMutation)
        executor.updateSchema(builder)

        then:
        executor.getSchema().mutationType == droidMutation
    }

}


================================================
FILE: src/test/groovy/org/crygier/graphql/MutableSchemaBuildTest.groovy
================================================
package org.crygier.graphql

import graphql.schema.GraphQLFieldDefinition
import graphql.schema.GraphQLObjectType
import graphql.schema.GraphQLSchema
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootContextLoader
import org.springframework.context.annotation.Configuration
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification

import javax.persistence.EntityManager

import static graphql.Scalars.GraphQLString

@Configuration
@ContextConfiguration(loader = SpringBootContextLoader, classes = TestApplication)
class MutableSchemaBuildTest extends Specification {

    @Autowired
    private EntityManager entityManager;

    private GraphQLSchema schema;

    private final GraphQLObjectType droidMutation = GraphQLObjectType.newObject()
            .name("CreateDroidMutation")
            .field(GraphQLFieldDefinition.newFieldDefinition()
                .name("name")
                .type(GraphQLString))
            .build()

    void setup() {
        schema = new GraphQLSchemaBuilder(entityManager).mutation(droidMutation).build()
    }

    def 'Can add a schema mutation'() {
        expect:
        schema.mutationType == droidMutation
    }

}


================================================
FILE: src/test/groovy/org/crygier/graphql/StarwarsQueryExecutorTest.groovy
================================================
package org.crygier.graphql

import org.crygier.graphql.model.starwars.Episode
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootContextLoader
import org.springframework.context.annotation.Configuration
import org.springframework.test.context.ContextConfiguration
import org.springframework.transaction.annotation.Transactional
import spock.lang.Specification

import javax.persistence.EntityManager

@Configuration
@ContextConfiguration(loader = SpringBootContextLoader, classes = TestApplication)
class StarwarsQueryExecutorTest extends Specification {

    @Autowired
    private GraphQLExecutor executor;

    def 'Gets just the names of all droids'() {
        given:
        def query = '''
        query HeroNameQuery {
          Droid {
            name
          }
        }
        '''
        def expected = [
                Droid: [
                        [ name: 'C-3PO' ],
                        [ name: 'R2-D2' ]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result['Droid'].sort() == expected['Droid']
    }

    def 'Query for droid by name'() {
        given:
        def query = '''
        {
          Droid(name: "C-3PO") {
            name
            primaryFunction
          }
        }
        '''
        def expected = [
                Droid: [
                        [ name: 'C-3PO', primaryFunction: 'Protocol' ]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected
    }

    def 'ManyToOne Join by ID'() {
        given:
        def query = '''
        {
            Human(id: "1000") {
                name
                homePlanet
                favoriteDroid {
                    name
                }
            }
        }
        '''
        def expected = [
                Human: [
                        [name:'Luke Skywalker', homePlanet:'Tatooine', favoriteDroid:[name:'C-3PO']]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected
    }
	
	def 'Nullable ManyToOne Join'() {
		given:
		def query = '''
        {
            Human(id: "1004") {
                name
                homePlanet
                favoriteDroid {
                    name
                }
            }
        }
        '''
		def expected = [
				Human: [
						[name:'Wilhuff Tarkin', homePlanet:null, favoriteDroid:null]
				]
		]

		when:
		def result = executor.execute(query).data

		then:
		result == expected
	}

    def 'OneToMany Join by ID'() {
        given:
        def query = '''
        {
            Human(id: "1000") {
                name
                homePlanet
                friends {
                    name
                }
            }
        }
        '''
        def expected = [
                Human: [
                        [name: 'Luke Skywalker', homePlanet: 'Tatooine', friends: [[name: 'Han Solo'], [name: 'Leia Organa'], [name: 'C-3PO'], [name: 'R2-D2']]]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected
    }

    def 'Query with parameter'() {
        given:
        def query = '''
        query humanQuery($id: String!) {
            Human(id: $id) {
                name
                homePlanet
            }
        }
        '''
        def expected = [
                Human: [
                        [name: 'Darth Vader', homePlanet: 'Tatooine']
                ]
        ]

        when:
        def result = executor.execute(query, [id: "1001"]).data

        then:
        result == expected
    }

    def 'Query with alias'() {
        given:
        def query = '''
        {
            luke: Human(id: "1000") {
                name
                homePlanet
            }
            leia: Human(id: "1003") {
                name
            }
        }
        '''
        def expected = [
                luke: [
                        [name: 'Luke Skywalker', homePlanet: 'Tatooine'],
                ],
                leia: [
                        [name: 'Leia Organa']
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected
    }

    def 'Allows us to use a fragment to avoid duplicating content'() {
        given:
        def query = """
        query UseFragment {
            luke: Human(id: "1000") {
                ...HumanFragment
            }
            leia: Human(id: "1003") {
                ...HumanFragment
            }
        }
        fragment HumanFragment on Human {
            name
            homePlanet
        }
        """
        def expected = [
                luke: [
                        [name: 'Luke Skywalker', homePlanet: 'Tatooine'],
                ],
                leia: [
                        [name: 'Leia Organa', homePlanet: 'Alderaan']
                ]
        ]
        when:
        def result = executor.execute(query).data

        then:
        result == expected
    }

    def 'Deep nesting'() {
        given:
        def query = '''
        {
            Droid(id: "2001") {
                name
                friends {
                    name
                    appearsIn
                    friends {
                        name
                    }
                }
            }
        }
        '''
        def expected = [
                Droid:[
                        [
                                name:'R2-D2',
                                friends:[
                                        [ name:'Luke Skywalker', appearsIn:['A_NEW_HOPE', 'EMPIRE_STRIKES_BACK', 'RETURN_OF_THE_JEDI', 'THE_FORCE_AWAKENS'], friends:[['name:Han Solo'], [name:'Leia Organa'], [name:'C-3PO'], [name:'R2-D2']]],
                                        [ name:'Han Solo', appearsIn:['A_NEW_HOPE', 'EMPIRE_STRIKES_BACK', 'RETURN_OF_THE_JEDI', 'THE_FORCE_AWAKENS'], friends:[[name:'Luke Skywalker'], [name:'Leia Organa'], [name:'R2-D2']]],
                                        [ name:'Leia Organa', appearsIn:['A_NEW_HOPE', 'EMPIRE_STRIKES_BACK', 'RETURN_OF_THE_JEDI', 'THE_FORCE_AWAKENS'], friends:[[name:'Luke Skywalker'], [name:'Han Solo'], [name:'C-3PO'], [name:'R2-D2']]]
                                ]
                        ]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result.toString() == expected.toString()
    }

    def 'Pagination at the root'() {
        given:
        def query = '''
        {
            HumanConnection(paginationRequest: { page: 1, size: 2 }) {
                totalPages
                totalElements
                content {
                    name
                }
            }
        }
        '''
        def expected = [
                HumanConnection: [
                        totalPages: 3,
                        totalElements: 5,
                        content: [
                                [ name: 'Darth Vader' ],
                                [ name: 'Luke Skywalker' ]
                        ]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected
    }

    def 'Pagination without content'() {
        given:
        def query = '''
        {
            HumanConnection(paginationRequest: { page: 1, size: 2}) {
                totalPages
                totalElements
            }
        }
        '''

        def expected = [
                HumanConnection: [
                        totalPages: 3,
                        totalElements: 5
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected
    }

    def 'Ordering Fields'() {
        given:
        def query = '''
        {
            Human {
                name(orderBy: DESC)
                homePlanet
            }
        }
        '''
        def expected = [
                Human: [
                    [ name: 'Wilhuff Tarkin', homePlanet: null],
                    [ name: 'Luke Skywalker', homePlanet: "Tatooine"],
                    [ name: 'Leia Organa', homePlanet: "Alderaan"],
                    [ name: 'Han Solo', homePlanet: null],
                    [ name: 'Darth Vader', homePlanet: "Tatooine"]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected
    }

    def 'Query by Collection of Enums at root level'() {
        // Semi-proper JPA: select distinct h from Human h join h.appearsIn ai where ai in (:episodes)

        given:
        def query = '''
        {
          Human(appearsIn: [THE_FORCE_AWAKENS]) {
            name
            appearsIn
          }
        }
        '''
        def expected = [
                Human: [
                    [ name: 'Leia Organa', appearsIn: [Episode.A_NEW_HOPE, Episode.EMPIRE_STRIKES_BACK, Episode.RETURN_OF_THE_JEDI, Episode.THE_FORCE_AWAKENS] ],
                    [ name: 'Luke Skywalker', appearsIn: [Episode.A_NEW_HOPE, Episode.EMPIRE_STRIKES_BACK, Episode.RETURN_OF_THE_JEDI, Episode.THE_FORCE_AWAKENS]],
                    [ name: 'Han Solo', appearsIn: [Episode.A_NEW_HOPE, Episode.EMPIRE_STRIKES_BACK, Episode.RETURN_OF_THE_JEDI, Episode.THE_FORCE_AWAKENS] ]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected;
    }

    def 'Query by restricting sub-object'() {
        given:
        def query = '''
        {
          Human {
            name
            gender(code: "Male") {
              description
            }
          }
        }
        '''
        def expected = [
                Human: [
                        [ name: 'Darth Vader', gender: [ description: "Male" ] ],                       
                        [ name: 'Luke Skywalker', gender: [ description: "Male" ]],
                        [ name: 'Han Solo', gender: [ description: "Male" ] ],
						[ name: 'Wilhuff Tarkin', gender: [ description: "Male" ]]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected;
    }

    def 'Query for searching by IntType (sequence field)'() {
        given:
        def query = '''
        {
          CodeList(sequence: 2) {
            id
            description
            active
            type
            sequence
          }
        }
        '''
        def expected = [
            CodeList: [
                [ id: 1, description: "Female", active: true, type: "org.crygier.graphql.model.starwars.Gender", sequence: 2]
            ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected;
    }

    def 'Query for searching by BooleanType (active field)'() {
        given:
        def query = '''
        {
          CodeList(active: true) {
            id
            description
            active
            type
            sequence
          }
        }
        '''
        def expected = [
                CodeList: [
                        [ id: 0, description: "Male", active: true, type: "org.crygier.graphql.model.starwars.Gender", sequence: 1],
                        [ id: 1, description: "Female", active: true, type: "org.crygier.graphql.model.starwars.Gender", sequence: 2]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected;
    }

    @Autowired
    private EntityManager em;

    @Transactional
    def 'JPA Sample Tester'() {
        when:
        //def query = em.createQuery("select h.id, h.name, h.gender.description from Human h where h.gender.code = 'Male'");
        def query = em.createQuery("select h, h.friends from Human h");
        //query.setParameter(1, Episode.THE_FORCE_AWAKENS);
        //query.setParameter("episodes", EnumSet.of(Episode.THE_FORCE_AWAKENS));
        def result = query.getResultList();
        //println JsonOutput.prettyPrint(JsonOutput.toJson(result));

        then:
        result;
    }

}


================================================
FILE: src/test/groovy/org/crygier/graphql/StarwarsSchemaBuildTest.groovy
================================================
package org.crygier.graphql

import graphql.Scalars
import graphql.schema.GraphQLSchema
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootContextLoader
import org.springframework.context.annotation.Configuration
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification

import javax.persistence.EntityManager

@Configuration
@ContextConfiguration(loader = SpringBootContextLoader, classes = TestApplication)
class StarwarsSchemaBuildTest extends Specification {

    @Autowired
    private EntityManager entityManager;

    private GraphQLSchemaBuilder builder;

    void setup() {
        builder = new GraphQLSchemaBuilder(entityManager);
    }

    def 'Correctly derives the schema from Given Entities'() {
        when:
        GraphQLSchema schema = builder.getGraphQLSchema();

        then:   "Ensure the result is returned"
        schema;

        then:   "Ensure that collections can be queried on"
        schema.getQueryType().getFieldDefinition("Droid").getArgument("appearsIn")

        then:   "Ensure Subobjects may be queried upon"
        schema.getQueryType().getFieldDefinition("CodeList").getArguments().size() == 6
        schema.getQueryType().getFieldDefinition("CodeList").getArgument("code").getType() == Scalars.GraphQLString
    }

}


================================================
FILE: src/test/groovy/org/crygier/graphql/TestApplication.groovy
================================================
package org.crygier.graphql

import groovy.transform.CompileStatic
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
@EnableAutoConfiguration
@EntityScan
@CompileStatic
class TestApplication {

    public static void main(String[] args) {
        ApplicationContext ac = SpringApplication.run(TestApplication.class, args);
    }

    @Bean
    public GraphQLExecutor graphQLExecutor() {
        return new GraphQLExecutor();
    }

    @Bean
    public GraphQlController() {
        return new GraphQlController();
    }

}


================================================
FILE: src/test/groovy/org/crygier/graphql/ThingQueryExecutorTest.groovy
================================================
package org.crygier.graphql

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootContextLoader
import org.springframework.context.annotation.Configuration
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification

@Configuration
@ContextConfiguration(loader = SpringBootContextLoader, classes = TestApplication)
class ThingQueryExecutorTest extends Specification {

    @Autowired
    private GraphQLExecutor executor

    def 'Gets all things'() {
        given:
        def query = '''
        query AllThingsQuery {
          Thing {
            id
            type
          }
        }
        '''
        def expected = [
                Thing: [
                   [ id: UUID.fromString("2d1ebc5b-7d27-4197-9cf0-e84451c5bbb1"), type:'Thing1' ]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected
    }

    def 'Query for thing by id'() {
        given:
        def query = '''
        query ThingByIdQuery {
          Thing(id: "2d1ebc5b-7d27-4197-9cf0-e84451c5bbb1") {
            id
            type
          }
        }
        '''
        def expected = [
                Thing: [
                        [ id: UUID.fromString("2d1ebc5b-7d27-4197-9cf0-e84451c5bbb1"), type:'Thing1' ]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected
    }

    def 'Query with parameter'() {
        given:
        def query = '''
       query ThingByIdQuery($id: UUID) {
          Thing(id: $id) {
            id
            type
          }
        }
        '''
        def expected = [
                Thing: [
                        [ id: UUID.fromString("2d1ebc5b-7d27-4197-9cf0-e84451c5bbb1"), type:'Thing1' ]
                ]
        ]

        when:
        def result = executor.execute(query, [id: "2d1ebc5b-7d27-4197-9cf0-e84451c5bbb1"]).data

        then:
        result == expected
    }

    def 'Query with alias'() {
        given:
        def query = '''
        {
         t1:  Thing(id: "2d1ebc5b-7d27-4197-9cf0-e84451c5bbb1") {
            id
            type
          }
        }
        '''
        def expected = [
                t1: [
                        [ id: UUID.fromString("2d1ebc5b-7d27-4197-9cf0-e84451c5bbb1"), type:'Thing1' ]
                ]
        ]

        when:
        def result = executor.execute(query).data

        then:
        result == expected
    }

}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/collections/CollectionTest.java
================================================
package org.crygier.graphql.model.collections;

import groovy.transform.CompileStatic;
import org.crygier.graphql.annotation.SchemaDocumentation;

import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.ArrayList;
import java.util.List;

@Entity
@CompileStatic
public class CollectionTest {

    //testing that the Schema Builder does not break
    //when building collection of non-enum objects

    @Id
    @SchemaDocumentation("Primary Key for the CollectionTest Class")
    String id;

    @SchemaDocumentation("A List of Strings")
    @ElementCollection(targetClass=String.class)
    List<String> codas = new ArrayList<String>();
}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/embeddings/EmbeddingId.java
================================================
package org.crygier.graphql.model.embeddings;

import org.crygier.graphql.model.starwars.Character;
import org.crygier.graphql.model.starwars.Episode;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import java.io.Serializable;

@Embeddable
class EmbeddingId implements Serializable {

    @ManyToOne
    @JoinColumn(name = "character_id")
    private Character character;

    @Column(name = "episode")
    private Episode episode;

    @Column(name = "age")
    private int age;

    public EmbeddingId(Character character, Episode episode, int age) {
        this.character = character;
        this.episode = episode;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        EmbeddingId that = (EmbeddingId) o;

        if (age != that.age) return false;
        if (character != null ? !character.equals(that.character) : that.character != null) return false;
        return episode == that.episode;
    }

    @Override
    public int hashCode() {
        int result = character != null ? character.hashCode() : 0;
        result = 31 * result + (episode != null ? episode.hashCode() : 0);
        result = 31 * result + age;
        return result;
    }
}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/embeddings/EmbeddingTest.java
================================================
package org.crygier.graphql.model.embeddings;

import groovy.transform.CompileStatic;
import org.crygier.graphql.annotation.GraphQLIgnore;
import org.hibernate.annotations.Target;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
@CompileStatic
public class EmbeddingTest {

    @EmbeddedId
    private EmbeddingId embeddingId;

}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/starwars/Character.groovy
================================================
package org.crygier.graphql.model.starwars

import groovy.transform.CompileStatic
import org.crygier.graphql.annotation.SchemaDocumentation

import javax.persistence.*

@Entity
@SchemaDocumentation("Abstract representation of an entity in the Star Wars Universe")
@CompileStatic
abstract class Character {

    @Id
    @SchemaDocumentation("Primary Key for the Character Class")
    String id;

    @SchemaDocumentation("Name of the character")
    String name;

    @SchemaDocumentation("Who are the known friends to this character")
    @ManyToMany
    @JoinTable(name="character_friends",
            joinColumns=@JoinColumn(name="source_id", referencedColumnName="id"),
            inverseJoinColumns=@JoinColumn(name="friend_id", referencedColumnName="id"))
    Collection<Character> friends;

    @SchemaDocumentation("What Star Wars episodes does this character appear in")
    @ElementCollection(targetClass = Episode)
    @Enumerated(EnumType.ORDINAL)
    Collection<Episode> appearsIn;

}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/starwars/CodeList.groovy
================================================
package org.crygier.graphql.model.starwars

import groovy.transform.CompileStatic
import org.crygier.graphql.annotation.SchemaDocumentation

import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.JoinColumn
import javax.persistence.ManyToOne

@Entity
@SchemaDocumentation("Database driven enumeration")
@CompileStatic
class CodeList {

    @Id
    @SchemaDocumentation("Primary Key for the Code List Class")
    Long id;

    String type;
    String code;
    Integer sequence;
    boolean active;
    String description;

    @ManyToOne
    @JoinColumn(name = "parent_id")
    CodeList parent;

}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/starwars/Droid.groovy
================================================
package org.crygier.graphql.model.starwars

import groovy.transform.CompileStatic
import org.crygier.graphql.annotation.GraphQLIgnore
import org.crygier.graphql.annotation.SchemaDocumentation

import javax.persistence.Entity

@Entity
@SchemaDocumentation("Represents an electromechanical robot in the Star Wars Universe")
@CompileStatic
class Droid extends Character {

    @SchemaDocumentation("Documents the primary purpose this droid serves")
    String primaryFunction;

    @GraphQLIgnore
    byte[] data;

}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/starwars/Episode.java
================================================
package org.crygier.graphql.model.starwars;

public enum Episode {

    PHANTOM_MENACE,
    ATTACK_OF_THE_CLONES,
    REVENGE_OF_THE_SITH,
    A_NEW_HOPE,
    EMPIRE_STRIKES_BACK,
    RETURN_OF_THE_JEDI,
    THE_FORCE_AWAKENS

}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/starwars/Human.groovy
================================================
package org.crygier.graphql.model.starwars

import groovy.transform.CompileStatic

import javax.persistence.Entity
import javax.persistence.FetchType
import javax.persistence.JoinColumn
import javax.persistence.ManyToOne

@Entity(name = "Human")
@CompileStatic
public class Human extends Character {

    String homePlanet;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "favorite_droid_id")
    Droid favoriteDroid;

    @ManyToOne
    @JoinColumn(name = "gender_code_id")
    CodeList gender;

}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/starwars/Spaceship.groovy
================================================
package org.crygier.graphql.model.starwars

import javax.persistence.*

import org.crygier.graphql.annotation.SchemaDocumentation
import org.crygier.graphql.model.users.DateAndUser

import groovy.transform.CompileStatic

@Entity
@SchemaDocumentation("Spaceships in the Star Wars Universe")
@CompileStatic
public class Spaceship {

	@Id
	@SchemaDocumentation("Primary Key for the Spaceship Class")
	public String id;

	@SchemaDocumentation("Name of the spaceship")
	String name;
	
	@Embedded
	@AttributeOverrides ([
		@AttributeOverride(name="date",column=@Column(name="createddate"))	
	])
	@AssociationOverrides ([
		@AssociationOverride(name="user",joinColumns=@JoinColumn(name="createduser"))
	])
	public DateAndUser created;
	
	@Embedded
	@AttributeOverrides ([
		@AttributeOverride(name="date",column=@Column(name="modifieddate"))
	])
	@AssociationOverrides ([
		@AssociationOverride(name="user",joinColumns=@JoinColumn(name="modifieduser"))
	])
	DateAndUser modified;
}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/users/DateAndUser.groovy
================================================
package org.crygier.graphql.model.users

import javax.persistence.Embeddable
import javax.persistence.ManyToOne

@Embeddable
public class DateAndUser {
	public Date date;
	@ManyToOne
	public User user;
}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/users/User.groovy
================================================
package org.crygier.graphql.model.users

import javax.persistence.Entity
import javax.persistence.Id

import org.crygier.graphql.annotation.SchemaDocumentation

import groovy.transform.CompileStatic

@Entity
@SchemaDocumentation("User who uses the application")
@CompileStatic
class User {

	@Id
	@SchemaDocumentation("Primary Key for the User Class")
	String id;
	
	String firstName;
	
	String lastName;
}


================================================
FILE: src/test/groovy/org/crygier/graphql/model/uuid/Thing.groovy
================================================
package org.crygier.graphql.model.uuid

import groovy.transform.CompileStatic
import org.crygier.graphql.annotation.SchemaDocumentation

import javax.persistence.Entity
import javax.persistence.Id

@Entity
@SchemaDocumentation("Database Thing with UUID field")
@CompileStatic
class Thing {

    @Id
    @SchemaDocumentation("Primary Key for the Thing Class")
    UUID id

    String type
}


================================================
FILE: src/test/resources/application.yaml
================================================
spring:
  jpa:
    hibernate.ddl-auto: create-drop
    show-sql: true
  h2:
    console.enabled: true

================================================
FILE: src/test/resources/data.sql
================================================
-- Insert Code Lists
insert into code_list (id, type, code, description, sequence, active) values
    (0, 'org.crygier.graphql.model.starwars.Gender', 'Male', 'Male', 1, true),
    (1, 'org.crygier.graphql.model.starwars.Gender', 'Female', 'Female', 2, true);

-- Insert Droids
insert into character (id, name, primary_function, dtype) values
    ('2000', 'C-3PO', 'Protocol', 'Droid'),
    ('2001', 'R2-D2', 'Astromech', 'Droid');

-- Insert Humans
insert into character (id, name, home_planet, favorite_droid_id, dtype, gender_code_id) values
    ('1000', 'Luke Skywalker', 'Tatooine', '2000', 'Human', 0),
    ('1001', 'Darth Vader', 'Tatooine', '2001', 'Human', 0),
    ('1002', 'Han Solo', NULL, NULL, 'Human', 0),
    ('1003', 'Leia Organa', 'Alderaan', NULL, 'Human', 1),
    ('1004', 'Wilhuff Tarkin', NULL, NULL, 'Human', 0);

-- Luke's friends
insert into character_friends (source_id, friend_id) values
    ('1000', '1002'),
    ('1000', '1003'),
    ('1000', '2000'),
    ('1000', '2001');

-- Luke Appears in
insert into character_appears_in (character_id, appears_in) values
    ('1000', 3),
    ('1000', 4),
    ('1000', 5),
    ('1000', 6);

-- Vader's friends
insert into character_friends (source_id, friend_id) values
    ('1001', '1004');

-- Vader Appears in
insert into character_appears_in (character_id, appears_in) values
    ('1001', 3),
    ('1001', 4),
    ('1001', 5);

-- Solo's friends
insert into character_friends (source_id, friend_id) values
    ('1002', '1000'),
    ('1002', '1003'),
    ('1002', '2001');

-- Solo Appears in
insert into character_appears_in (character_id, appears_in) values
    ('1002', 3),
    ('1002', 4),
    ('1002', 5),
    ('1002', 6);

-- Leia's friends
insert into character_friends (source_id, friend_id) values
    ('1003', '1000'),
    ('1003', '1002'),
    ('1003', '2000'),
    ('1003', '2001');

-- Leia Appears in
insert into character_appears_in (character_id, appears_in) values
    ('1003', 3),
    ('1003', 4),
    ('1003', 5),
    ('1003', 6);

-- Wilhuff's friends
insert into character_friends (source_id, friend_id) values
    ('1004', '1001');

-- Wilhuff Appears in
insert into character_appears_in (character_id, appears_in) values
    ('1004', 3);

-- C3PO's friends
insert into character_friends (source_id, friend_id) values
    ('2000', '1000'),
    ('2000', '1002'),
    ('2000', '1003'),
    ('2000', '2001');

-- C3PO Appears in
insert into character_appears_in (character_id, appears_in) values
    ('2000', 3),
    ('2000', 4),
    ('2000', 5),
    ('2000', 6);

-- R2's friends
insert into character_friends (source_id, friend_id) values
    ('2001', '1000'),
    ('2001', '1002'),
    ('2001', '1003');

-- R2 Appears in
insert into character_appears_in (character_id, appears_in) values
    ('2001', 3),
    ('2001', 4),
    ('2001', 5),
    ('2001', 6);

-- Things
insert into thing (id, type) values
    ('2D1EBC5B7D2741979CF0E84451C5BBB1', 'Thing1');

-- User
insert into user(id, first_name, last_name) values
	('1000','Bob', 'Austin');
	
insert into spaceship(id, name, createddate,createduser) values
	('1000','X-Wing', sysdate, '1000');

================================================
FILE: src/test/resources/static/index.html
================================================
<!--
 *  Copyright (c) 2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the license found in the
 *  LICENSE file in the root directory of this source tree.
 *
-->
<!DOCTYPE html>
<html>
  <head>
    <link href="//cdn.jsdelivr.net/graphiql/0.4.4/graphiql.css" rel="stylesheet">
    <script src="//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js"></script>
    <script src="//cdn.jsdelivr.net/react/0.14.2/react.min.js"></script>
    <script src="//cdn.jsdelivr.net/react/0.14.2/react-dom.min.js"></script>
    <script src="//cdn.jsdelivr.net/graphiql/0.4.5/graphiql.min.js"></script>
  </head>
  <body>
    Loading...
    <script>

      /**
       * This GraphiQL example illustrates how to use some of GraphiQL's props
       * in order to enable reading and updating the URL parameters, making
       * link sharing of queries a little bit easier.
       *
       * This is only one example of this kind of feature, GraphiQL exposes
       * various React params to enable interesting integrations.
       */

      // Parse the search string to get url parameters.
      var search = window.location.search;
      var parameters = {};
      search.substr(1).split('&').forEach(function (entry) {
        var eq = entry.indexOf('=');
        if (eq >= 0) {
          parameters[decodeURIComponent(entry.slice(0, eq))] =
            decodeURIComponent(entry.slice(eq + 1));
        }
      });

      // if variables was provided, try to format it.
      if (parameters.variables) {
        try {
          parameters.variables =
            JSON.stringify(JSON.parse(parameters.variables), null, 2);
        } catch (e) {
          // Do nothing, we want to display the invalid JSON as a string, rather
          // than present an error.
        }
      }

      // When the query and variables string is edited, update the URL bar so
      // that it can be easily shared
      function onEditQuery(newQuery) {
        parameters.query = newQuery;
        updateURL();
      }

      function onEditVariables(newVariables) {
        parameters.variables = newVariables;
        updateURL();
      }

      function updateURL() {
        var newSearch = '?' + Object.keys(parameters).map(function (key) {
          return encodeURIComponent(key) + '=' +
            encodeURIComponent(parameters[key]);
        }).join('&');
        history.replaceState(null, null, newSearch);
      }

      // Defines a GraphQL fetcher using the fetch API.
      function graphQLFetcher(graphQLParams) {
        return fetch(window.location.origin + '/graphql', {
          method: 'post',
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(graphQLParams),
          credentials: 'include',
        }).then(function (response) {
          return response.json();
        });
      }

      // Render <GraphiQL /> into the body.
      ReactDOM.render(
        React.createElement(GraphiQL, {
          fetcher: graphQLFetcher,
          query: parameters.query,
          variables: parameters.variables,
          onEditQuery: onEditQuery,
          onEditVariables: onEditVariables
        }),
        document.body
      );
    </script>
  </body>
</html>
Download .txt
gitextract_gdex4ibc/

├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── bintray.json
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src/
    ├── main/
    │   └── java/
    │       └── org/
    │           └── crygier/
    │               └── graphql/
    │                   ├── AttributeMapper.java
    │                   ├── ExtendedJpaDataFetcher.java
    │                   ├── GraphQLExecutor.java
    │                   ├── GraphQLSchemaBuilder.java
    │                   ├── IdentityCoercing.java
    │                   ├── JavaScalars.java
    │                   ├── JpaDataFetcher.java
    │                   └── annotation/
    │                       ├── GraphQLIgnore.java
    │                       └── SchemaDocumentation.java
    └── test/
        ├── groovy/
        │   └── org/
        │       └── crygier/
        │           └── graphql/
        │               ├── EmbeddedQueryExecutorTest.groovy
        │               ├── EmbeddedSchemaBuildTest.groovy
        │               ├── GraphQlController.groovy
        │               ├── JavaScalarsTest.groovy
        │               ├── MutableQueryExecutorTest.groovy
        │               ├── MutableSchemaBuildTest.groovy
        │               ├── StarwarsQueryExecutorTest.groovy
        │               ├── StarwarsSchemaBuildTest.groovy
        │               ├── TestApplication.groovy
        │               ├── ThingQueryExecutorTest.groovy
        │               └── model/
        │                   ├── collections/
        │                   │   └── CollectionTest.java
        │                   ├── embeddings/
        │                   │   ├── EmbeddingId.java
        │                   │   └── EmbeddingTest.java
        │                   ├── starwars/
        │                   │   ├── Character.groovy
        │                   │   ├── CodeList.groovy
        │                   │   ├── Droid.groovy
        │                   │   ├── Episode.java
        │                   │   ├── Human.groovy
        │                   │   └── Spaceship.groovy
        │                   ├── users/
        │                   │   ├── DateAndUser.groovy
        │                   │   └── User.groovy
        │                   └── uuid/
        │                       └── Thing.groovy
        └── resources/
            ├── application.yaml
            ├── data.sql
            └── static/
                └── index.html
Download .txt
SYMBOL INDEX (93 symbols across 11 files)

FILE: src/main/java/org/crygier/graphql/AttributeMapper.java
  type AttributeMapper (line 10) | @FunctionalInterface
    method getBasicAttributeType (line 20) | Optional<GraphQLType> getBasicAttributeType(Class javaType);

FILE: src/main/java/org/crygier/graphql/ExtendedJpaDataFetcher.java
  class ExtendedJpaDataFetcher (line 23) | public class ExtendedJpaDataFetcher extends JpaDataFetcher {
    method ExtendedJpaDataFetcher (line 25) | public ExtendedJpaDataFetcher(EntityManager entityManager, EntityType<...
    method get (line 29) | @Override
    method getCountQuery (line 57) | private TypedQuery<Long> getCountQuery(DataFetchingEnvironment environ...
    method getSelectionField (line 70) | private Optional<Field> getSelectionField(Field field, String fieldNam...
    method extractPageInformation (line 74) | private PageInformation extractPageInformation(DataFetchingEnvironment...
    class PageInformation (line 89) | private static final class PageInformation {
      method PageInformation (line 93) | public PageInformation(Integer page, Integer size) {

FILE: src/main/java/org/crygier/graphql/GraphQLExecutor.java
  class GraphQLExecutor (line 22) | public class GraphQLExecutor {
    method GraphQLExecutor (line 30) | protected GraphQLExecutor() {
    method GraphQLExecutor (line 40) | public GraphQLExecutor(EntityManager entityManager) {
    method GraphQLExecutor (line 52) | public GraphQLExecutor(EntityManager entityManager, Collection<Attribu...
    method createGraphQL (line 57) | @PostConstruct
    method createGraphQL (line 62) | protected synchronized void createGraphQL(Collection<AttributeMapper> ...
    method getGraphQLSchema (line 77) | public GraphQLSchema getGraphQLSchema() {
    method execute (line 81) | @Transactional
    method execute (line 86) | @Transactional
    method getBuilder (line 98) | public GraphQLSchema.Builder getBuilder() {
    method getSchema (line 106) | public GraphQLSchema getSchema() {
    method updateSchema (line 117) | public GraphQLExecutor updateSchema(GraphQLSchema.Builder builder) {
    method updateSchema (line 131) | public GraphQLExecutor updateSchema(GraphQLSchema.Builder builder, Col...

FILE: src/main/java/org/crygier/graphql/GraphQLSchemaBuilder.java
  class GraphQLSchemaBuilder (line 55) | public class GraphQLSchemaBuilder extends GraphQLSchema.Builder {
    method GraphQLSchemaBuilder (line 71) | public GraphQLSchemaBuilder(EntityManager entityManager) {
    method GraphQLSchemaBuilder (line 79) | public GraphQLSchemaBuilder(EntityManager entityManager, Collection<At...
    method populateStandardAttributeMappers (line 88) | private void populateStandardAttributeMappers() {
    method createStandardAttributeMapper (line 96) | private AttributeMapper createStandardAttributeMapper(final Class<?> a...
    method getGraphQLSchema (line 109) | @Deprecated()
    method getQueryType (line 114) | GraphQLObjectType getQueryType() {
    method getQueryFieldDefinition (line 123) | GraphQLFieldDefinition getQueryFieldDefinition(EntityType<?> entityTyp...
    method getQueryEmbeddedFieldDefinition (line 133) | GraphQLFieldDefinition getQueryEmbeddedFieldDefinition(EmbeddableType<...
    method getQueryFieldPageableDefinition (line 143) | private GraphQLFieldDefinition getQueryFieldPageableDefinition(EntityT...
    method getArgument (line 161) | private Stream<GraphQLArgument> getArgument(Attribute attribute) {
    method getObjectType (line 176) | GraphQLObjectType getObjectType(EntityType<?> entityType) {
    method getObjectType (line 191) | GraphQLObjectType getObjectType(EmbeddableType<?> embeddableType) {
    method getObjectField (line 208) | private Stream<GraphQLFieldDefinition> getObjectField(Attribute attrib...
    method findBasicAttributes (line 242) | private Stream<Attribute> findBasicAttributes(Collection<Attribute> at...
    method getBasicAttributeType (line 246) | private GraphQLType getBasicAttributeType(Class javaType) {
    method getAttributeType (line 277) | private Stream<GraphQLType> getAttributeType(Attribute attribute) {
    method isValidInput (line 306) | private boolean isValidInput(Attribute attribute) {
    method getSchemaDocumentation (line 312) | private String getSchemaDocumentation(Member member) {
    method getSchemaDocumentation (line 320) | private String getSchemaDocumentation(AnnotatedElement annotatedElemen...
    method isNotIgnored (line 329) | private boolean isNotIgnored(Attribute attribute) {
    method isNotIgnored (line 333) | private boolean isNotIgnored(EmbeddableType<?> embeddableType) {
    method isNotIgnored (line 337) | private boolean isNotIgnored(EntityType entityType) {
    method isNotIgnored (line 341) | private boolean isNotIgnored(Member member) {
    method isNotIgnored (line 345) | private boolean isNotIgnored(AnnotatedElement annotatedElement) {
    method getTypeFromJavaType (line 354) | private GraphQLType getTypeFromJavaType(Class clazz) {
    method setIdentityCoercing (line 380) | private void setIdentityCoercing(GraphQLType type) {

FILE: src/main/java/org/crygier/graphql/IdentityCoercing.java
  class IdentityCoercing (line 5) | public class IdentityCoercing implements Coercing{
    method serialize (line 7) | @Override
    method parseValue (line 12) | @Override
    method parseLiteral (line 17) | @Override

FILE: src/main/java/org/crygier/graphql/JavaScalars.java
  class JavaScalars (line 22) | public class JavaScalars {
    method serialize (line 26) | @Override
    method parseValue (line 40) | @Override
    method parseLiteral (line 45) | @Override
    method parseLongToLocalDateTime (line 56) | private LocalDateTime parseLongToLocalDateTime(long input) {
    method parseStringToLocalDateTime (line 60) | private LocalDateTime parseStringToLocalDateTime(String input) {
    method serialize (line 72) | @Override
    method parseValue (line 81) | @Override
    method parseLiteral (line 92) | @Override
    method serialize (line 103) | @Override
    method parseValue (line 117) | @Override
    method parseLiteral (line 122) | @Override
    method parseLongToLocalDate (line 133) | private LocalDate parseLongToLocalDate(long input) {
    method parseStringToLocalDate (line 137) | private LocalDate parseStringToLocalDate(String input) {
    method serialize (line 149) | @Override
    method parseValue (line 163) | @Override
    method parseLiteral (line 168) | @Override
    method parseStringToDate (line 179) | private Date parseStringToDate(String input) {
    method serialize (line 191) | @Override
    method parseValue (line 199) | @Override
    method parseLiteral (line 207) | @Override
    method parseStringToUUID (line 215) | private UUID parseStringToUUID(String input) {

FILE: src/main/java/org/crygier/graphql/JpaDataFetcher.java
  class JpaDataFetcher (line 16) | public class JpaDataFetcher implements DataFetcher {
    method JpaDataFetcher (line 21) | public JpaDataFetcher(EntityManager entityManager, EntityType<?> entit...
    method get (line 26) | @Override
    method getQuery (line 31) | protected TypedQuery getQuery(DataFetchingEnvironment environment, Fie...
    method getPredicate (line 81) | private Predicate getPredicate(CriteriaBuilder cb, Root root, DataFetc...
    method convertValue (line 109) | protected Object convertValue(DataFetchingEnvironment environment, Arg...
    method getJavaType (line 138) | private Class getJavaType(DataFetchingEnvironment environment, Argumen...
    method getAttribute (line 147) | private Attribute getAttribute(DataFetchingEnvironment environment, Ar...
    method getEntityType (line 154) | private EntityType getEntityType(GraphQLObjectType objectType) {
    method getObjectType (line 158) | private GraphQLObjectType getObjectType(DataFetchingEnvironment enviro...

FILE: src/test/groovy/org/crygier/graphql/model/collections/CollectionTest.java
  class CollectionTest (line 12) | @Entity

FILE: src/test/groovy/org/crygier/graphql/model/embeddings/EmbeddingId.java
  class EmbeddingId (line 12) | @Embeddable
    method EmbeddingId (line 25) | public EmbeddingId(Character character, Episode episode, int age) {
    method equals (line 31) | @Override
    method hashCode (line 43) | @Override

FILE: src/test/groovy/org/crygier/graphql/model/embeddings/EmbeddingTest.java
  class EmbeddingTest (line 11) | @Entity

FILE: src/test/groovy/org/crygier/graphql/model/starwars/Episode.java
  type Episode (line 3) | public enum Episode {
Condensed preview — 44 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (111K chars).
[
  {
    "path": ".gitignore",
    "chars": 79,
    "preview": ".gradle/\n.idea/\nbin/\nbuild/\n*.iml\n.classpath\n.project\n.settings/\nclasses/\nout/\n"
  },
  {
    "path": ".travis.yml",
    "chars": 805,
    "preview": "language: java\njdk:\n  - oraclejdk8\ndeploy:\n  provider: bintray\n  file: bintray.json\n  user: jcrygier\n  key:\n    secure: "
  },
  {
    "path": "LICENSE",
    "chars": 1086,
    "preview": "MIT License\n\nCopyright (c) 2017 John Crygier and Contributors\n\nPermission is hereby granted, free of charge, to any pers"
  },
  {
    "path": "README.md",
    "chars": 4411,
    "preview": "GraphQL for JPA\n===============\n\nIf you're already using JPA, then you already have a schema defined...don't define it a"
  },
  {
    "path": "bintray.json",
    "chars": 340,
    "preview": "{\n    \"package\": {\n        \"name\": \"GraphQL-JPA\",\n        \"repo\": \"maven\",\n        \"subject\": \"jcrygier\"\n    },\n    \"ver"
  },
  {
    "path": "build.gradle",
    "chars": 2303,
    "preview": "apply plugin: 'groovy'\napply plugin: 'eclipse'\napply plugin: 'idea'\napply plugin: 'maven'\napply plugin: 'maven-publish'\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 230,
    "preview": "#Tue Sep 15 19:06:52 CDT 2015\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "gradlew",
    "chars": 5080,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "gradlew.bat",
    "chars": 2314,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "src/main/java/org/crygier/graphql/AttributeMapper.java",
    "chars": 505,
    "preview": "package org.crygier.graphql;\n\nimport graphql.schema.GraphQLType;\n\nimport java.util.Optional;\n\n/**\n * (Functional) Interf"
  },
  {
    "path": "src/main/java/org/crygier/graphql/ExtendedJpaDataFetcher.java",
    "chars": 4595,
    "preview": "package org.crygier.graphql;\n\nimport graphql.language.Argument;\nimport graphql.language.Field;\nimport graphql.language.I"
  },
  {
    "path": "src/main/java/org/crygier/graphql/GraphQLExecutor.java",
    "chars": 5097,
    "preview": "package org.crygier.graphql;\n\nimport graphql.ExecutionInput;\nimport graphql.ExecutionResult;\nimport graphql.GraphQL;\nimp"
  },
  {
    "path": "src/main/java/org/crygier/graphql/GraphQLSchemaBuilder.java",
    "chars": 20643,
    "preview": "package org.crygier.graphql;\n\nimport graphql.Scalars;\nimport graphql.schema.GraphQLArgument;\nimport graphql.schema.Graph"
  },
  {
    "path": "src/main/java/org/crygier/graphql/IdentityCoercing.java",
    "chars": 382,
    "preview": "package org.crygier.graphql;\n\nimport graphql.schema.Coercing;\n\npublic class IdentityCoercing implements Coercing{\n\n    @"
  },
  {
    "path": "src/main/java/org/crygier/graphql/JavaScalars.java",
    "chars": 7861,
    "preview": "package org.crygier.graphql;\n\nimport graphql.language.IntValue;\nimport graphql.language.StringValue;\nimport graphql.sche"
  },
  {
    "path": "src/main/java/org/crygier/graphql/JpaDataFetcher.java",
    "chars": 7623,
    "preview": "package org.crygier.graphql;\n\nimport graphql.language.*;\nimport graphql.schema.*;\n\nimport javax.persistence.EntityManage"
  },
  {
    "path": "src/main/java/org/crygier/graphql/annotation/GraphQLIgnore.java",
    "chars": 367,
    "preview": "package org.crygier.graphql.annotation;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\nimp"
  },
  {
    "path": "src/main/java/org/crygier/graphql/annotation/SchemaDocumentation.java",
    "chars": 395,
    "preview": "package org.crygier.graphql.annotation;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\nimp"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/EmbeddedQueryExecutorTest.groovy",
    "chars": 977,
    "preview": "package org.crygier.graphql\n\nimport javax.persistence.EntityManager\n\nimport org.springframework.beans.factory.annotation"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/EmbeddedSchemaBuildTest.groovy",
    "chars": 1680,
    "preview": "package org.crygier.graphql\n\nimport graphql.schema.GraphQLObjectType\nimport org.springframework.beans.factory.annotation"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/GraphQlController.groovy",
    "chars": 1076,
    "preview": "package org.crygier.graphql\n\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport graphql.ExecutionResult\nimport gr"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/JavaScalarsTest.groovy",
    "chars": 2590,
    "preview": "package org.crygier.graphql\n\nimport graphql.schema.Coercing\nimport spock.lang.Specification\n\nimport java.time.Instant\nim"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/MutableQueryExecutorTest.groovy",
    "chars": 1218,
    "preview": "package org.crygier.graphql\n\nimport graphql.schema.GraphQLFieldDefinition\nimport graphql.schema.GraphQLObjectType\nimport"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/MutableSchemaBuildTest.groovy",
    "chars": 1265,
    "preview": "package org.crygier.graphql\n\nimport graphql.schema.GraphQLFieldDefinition\nimport graphql.schema.GraphQLObjectType\nimport"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/StarwarsQueryExecutorTest.groovy",
    "chars": 12389,
    "preview": "package org.crygier.graphql\n\nimport org.crygier.graphql.model.starwars.Episode\nimport org.springframework.beans.factory."
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/StarwarsSchemaBuildTest.groovy",
    "chars": 1366,
    "preview": "package org.crygier.graphql\n\nimport graphql.Scalars\nimport graphql.schema.GraphQLSchema\nimport org.springframework.beans"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/TestApplication.groovy",
    "chars": 839,
    "preview": "package org.crygier.graphql\n\nimport groovy.transform.CompileStatic\nimport org.springframework.boot.SpringApplication\nimp"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/ThingQueryExecutorTest.groovy",
    "chars": 2577,
    "preview": "package org.crygier.graphql\n\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.bo"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/collections/CollectionTest.java",
    "chars": 704,
    "preview": "package org.crygier.graphql.model.collections;\n\nimport groovy.transform.CompileStatic;\nimport org.crygier.graphql.annota"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/embeddings/EmbeddingId.java",
    "chars": 1397,
    "preview": "package org.crygier.graphql.model.embeddings;\n\nimport org.crygier.graphql.model.starwars.Character;\nimport org.crygier.g"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/embeddings/EmbeddingTest.java",
    "chars": 390,
    "preview": "package org.crygier.graphql.model.embeddings;\n\nimport groovy.transform.CompileStatic;\nimport org.crygier.graphql.annotat"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/starwars/Character.groovy",
    "chars": 999,
    "preview": "package org.crygier.graphql.model.starwars\n\nimport groovy.transform.CompileStatic\nimport org.crygier.graphql.annotation."
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/starwars/CodeList.groovy",
    "chars": 628,
    "preview": "package org.crygier.graphql.model.starwars\n\nimport groovy.transform.CompileStatic\nimport org.crygier.graphql.annotation."
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/starwars/Droid.groovy",
    "chars": 514,
    "preview": "package org.crygier.graphql.model.starwars\n\nimport groovy.transform.CompileStatic\nimport org.crygier.graphql.annotation."
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/starwars/Episode.java",
    "chars": 229,
    "preview": "package org.crygier.graphql.model.starwars;\n\npublic enum Episode {\n\n    PHANTOM_MENACE,\n    ATTACK_OF_THE_CLONES,\n    RE"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/starwars/Human.groovy",
    "chars": 514,
    "preview": "package org.crygier.graphql.model.starwars\n\nimport groovy.transform.CompileStatic\n\nimport javax.persistence.Entity\nimpor"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/starwars/Spaceship.groovy",
    "chars": 975,
    "preview": "package org.crygier.graphql.model.starwars\n\nimport javax.persistence.*\n\nimport org.crygier.graphql.annotation.SchemaDocu"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/users/DateAndUser.groovy",
    "chars": 204,
    "preview": "package org.crygier.graphql.model.users\n\nimport javax.persistence.Embeddable\nimport javax.persistence.ManyToOne\n\n@Embedd"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/users/User.groovy",
    "chars": 407,
    "preview": "package org.crygier.graphql.model.users\n\nimport javax.persistence.Entity\nimport javax.persistence.Id\n\nimport org.crygier"
  },
  {
    "path": "src/test/groovy/org/crygier/graphql/model/uuid/Thing.groovy",
    "chars": 390,
    "preview": "package org.crygier.graphql.model.uuid\n\nimport groovy.transform.CompileStatic\nimport org.crygier.graphql.annotation.Sche"
  },
  {
    "path": "src/test/resources/application.yaml",
    "chars": 101,
    "preview": "spring:\n  jpa:\n    hibernate.ddl-auto: create-drop\n    show-sql: true\n  h2:\n    console.enabled: true"
  },
  {
    "path": "src/test/resources/data.sql",
    "chars": 3137,
    "preview": "-- Insert Code Lists\ninsert into code_list (id, type, code, description, sequence, active) values\n    (0, 'org.crygier.g"
  },
  {
    "path": "src/test/resources/static/index.html",
    "chars": 3285,
    "preview": "<!--\n *  Copyright (c) 2015, Facebook, Inc.\n *  All rights reserved.\n *\n *  This source code is licensed under the licen"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the jcrygier/graphql-jpa GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 44 files (101.5 KB), approximately 24.7k tokens, and a symbol index with 93 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!