All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yahoo.elide.test.graphql.GraphQLDSL Maven / Gradle / Ivy

/*
 * Copyright 2019, Yahoo Inc.
 * Licensed under the Apache License, Version 2.0
 * See LICENSE file in project root for terms.
 */
package com.yahoo.elide.test.graphql;

import com.yahoo.elide.test.graphql.elements.Argument;
import com.yahoo.elide.test.graphql.elements.Arguments;
import com.yahoo.elide.test.graphql.elements.Definition;
import com.yahoo.elide.test.graphql.elements.Document;
import com.yahoo.elide.test.graphql.elements.Edges;
import com.yahoo.elide.test.graphql.elements.Field;
import com.yahoo.elide.test.graphql.elements.Mutation;
import com.yahoo.elide.test.graphql.elements.Node;
import com.yahoo.elide.test.graphql.elements.Query;
import com.yahoo.elide.test.graphql.elements.Selection;
import com.yahoo.elide.test.graphql.elements.SelectionSet;
import com.yahoo.elide.test.graphql.elements.VariableDefinition;
import com.yahoo.elide.test.graphql.elements.VariableDefinitions;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * {@link GraphQLDSL} programmatically construct GraphQL query(excluding query variables)
 * and serializes it to a GraphQL query string.
 * 

* For example, *

 * {@code
 * String graphQLQuery = document(
 *         query(
 *                 "myQuery",
 *                 variableDefinitions(
 *                         variableDefinition("bookId", "[String]")
 *                 ),
 *                 selections(
 *                         field(
 *                                 "book",
 *                                 arguments(
 *                                         argument("ids", "$bookId")
 *                                 ),
 *                                 selections(
 *                                         field("id"),
 *                                         field("title"),
 *                                         field(
 *                                                 "authors",
 *                                                 selection(
 *                                                         field("name")
 *                                                 )
 *                                         )
 *                                 )
 *                         )
 *                 )
 *                 )
 *         ).toQuery();
 * }
 * 
* will produces the following query *
 * {@code
 * query myQuery($bookId: [String]) {
 *     book(ids: $bookId) {
 *         edges {
 *             node {
 *                 id
 *                 title
 *                 authors {
 *                     edges {
 *                         node {
 *                             name
 *                         }
 *                     }
 *                 }
 *             }
 *         }
 *     }
 * }
 * }
 * 
* In addition, {@link GraphQLDSL} also allows programmatically constructing GraphQL response data. For example, *
 * {@code
 * document(
 *         selection(
 *                 field(
 *                         "book",
 *                         selections(
 *                                 field("id", "3"),
 *                                 field("title", "Doctor Zhivago"),
 *                                 field(
 *                                         "publisher",
 *                                         selection(
 *                                                 field("id", "2")
 *                                         )
 *                                 )
 *                         ),
 *                         selections(
 *                                 field("id", "1"),
 *                                 field("title", "Libro Uno"),
 *                                 field(
 *                                         "publisher",
 *                                         selection(
 *                                                 field("id", "1")
 *                                         )
 *                                 )
 *                         ),
 *                         selections(
 *                                 field("id", "2"),
 *                                 field("title", "Libro Dos"),
 *                                 field(
 *                                         "publisher",
 *                                         selection(
 *                                                 field("id", "1")
 *                                         )
 *                                 )
 *                         )
 *                 )
 *         )
 * ).toResponse();
 * }
 * 
* produces the following response: *
 * {@code
 * {
 *     "data":{
 *         "book":{
 *             "edges":[
 *                 {
 *                     "node":{
 *                         "id":"3",
 *                         "title":"Doctor Zhivago",
 *                         "publisher":{
 *                             "edges":[
 *                                 {
 *                                     "node":{
 *                                         "id":"2"
 *                                     }
 *                                 }
 *                             ]
 *                         }
 *                     }
 *                 },
 *                 {
 *                     "node":{
 *                         "id":"1",
 *                         "title":"Libro Uno",
 *                         "publisher":{
 *                             "edges":[
 *                                 {
 *                                     "node":{
 *                                         "id":"1"
 *                                     }
 *                                 }
 *                             ]
 *                         }
 *                     }
 *                 },
 *                 {
 *                     "node":{
 *                         "id":"2",
 *                         "title":"Libro Dos",
 *                         "publisher":{
 *                             "edges":[
 *                                 {
 *                                     "node":{
 *                                         "id":"1"
 *                                     }
 *                                 }
 *                             ]
 *                         }
 *                     }
 *                 }
 *             ]
 *         }
 *     }
 * }
 * }
 * 
* Note that {@link GraphQLDSL} follows Relay's connection pattern(https://graphql.org/learn/pagination/). */ public final class GraphQLDSL { public static final boolean QUOTE_VALUE = true; public static final boolean UNQUOTED_VALUE = false; /** * Jackson-serializes objects. */ private static final ObjectMapper BASE_MAPPER = new ObjectMapper() .setSerializationInclusion(JsonInclude.Include.NON_NULL) .setSerializationInclusion(JsonInclude.Include.NON_DEFAULT) .setSerializationInclusion(JsonInclude.Include.NON_EMPTY); /** * Returns the JSON representation of an object. * * @param object Object to be serialized * * @return a string * * @throws IllegalStateException */ public static String toJson(Object object) { try { return BASE_MAPPER.writer().writeValueAsString(object); } catch (JsonProcessingException exception) { throw new IllegalArgumentException(exception); } } /** * Creates a GraphQL query. * * @param definitions An variable-lengthed array of {@link Definition}s that composes a complete GraphQL query. * * @return a serializable GraphQL query object */ public static Document document(Definition... definitions) { return new Document(Arrays.asList(definitions)); } /** * Creates a single root-entity selection spec. * * @param selection The single selection spec object * * @return a definition of a multi-definitions GraphQL query * * @see Field Selection */ public static SelectionSet selection(Selection selection) { return new SelectionSet(new LinkedHashSet<>(Collections.singleton(selection))); } /** * Creates a multi-root-entities selections spec. * * @param selections An variable-sized array of selection spec objects * * @return a definition of a multi-definitions GraphQL query * * @see Field Selection */ public static SelectionSet selections(Selection... selections) { return new SelectionSet(Arrays.stream(selections).collect(Collectors.toCollection(LinkedHashSet::new))); } /** * Constructs a mutation. * * @param name Mutation name * @param variableDefinitions Optional variables * @param selectionSet Selected fields * * @return a mutation */ public static Mutation mutation(String name, VariableDefinitions variableDefinitions, SelectionSet selectionSet) { return new Mutation(name, variableDefinitions, selectionSet); } /** * Constructs a mutation. * * @param selectionSet Selected fields * * @return a mutation */ public static Mutation mutation(SelectionSet selectionSet) { return new Mutation(null, null, selectionSet); } /** * Constructs a named query. * * @param name Query name * @param variableDefinitions Optional variables * @param selectionSet Selected fields * * @return a named query */ public static Query query(String name, VariableDefinitions variableDefinitions, SelectionSet selectionSet) { return new Query(name, variableDefinitions, selectionSet); } /** * Constructs a named query. * * @param selectionSet Selected fields * * @return a named query */ public static Query query(SelectionSet selectionSet) { return new Query(null, null, selectionSet); } /** * Creates a collection of GraphQL variable definitions. * * @param variableDefinitions A variable-sized array of {@link VariableDefinition}s * * @return A collection of GraphQL variable definitions * * @see Variables */ public static VariableDefinitions variableDefinitions(VariableDefinition... variableDefinitions) { return new VariableDefinitions(Arrays.asList(variableDefinitions)); } /** * Creates a single GraphQL variable definition without default value. * * @param variable A string (without "$" sign) representing the name of the variable * @param type A simplified String representation of the aforementioned type literal. * * @return A single GraphQL variable definition * * @see Variables */ public static VariableDefinition variableDefinition(String variable, String type) { return new VariableDefinition(variable, type, null); } /** * Constructs a response field with string value. * * @param name Field name * @param value Field value * * @return a field */ public static Selection field(String name, String value) { return new Field(null, name, Arguments.emptyArgument(), Field.quoteValue(value)); } /** * Constructs a response field with numeric value. * * @param name Field name * @param value Field value * * @return a field */ public static Selection field(String name, Number value) { return new Field(null, name, Arguments.emptyArgument(), value); } /** * Constructs a response field with boolean value. * * @param name Field name * @param value Field value * * @return a field */ public static Selection field(String name, Boolean value) { return new Field(null, name, Arguments.emptyArgument(), value); } /** * Constructs a scalar response field. * * @param name Field name * @param value Field value * @param quoted Weather value is quoted * * @return a field */ public static Selection field(String name, String value, boolean quoted) { return new Field(null, name, Arguments.emptyArgument(), quoted ? Field.quoteValue(value) : value); } /** * Creates a request selection without {@link Argument}s. * * @param name The name of the selected entity/field that would appear in a GraphQL query * @param selectionSet The fields of the entity that are selected * * @return a top-level selection * * @see Fields * @see Object Types and Fields */ public static Selection field(String name, SelectionSet... selectionSet) { return field(null, name, selectionSet); } public static Selection field(String alias, String name, SelectionSet... selectionSet) { List ss = ImmutableList.copyOf(selectionSet); return new Field(alias, name, Arguments.emptyArgument(), relayWrap(ss)); } /** * Creates a single entity(object field) selection. * * @param name The name of the selected entity/field that would appear in a GraphQL query * @param arguments The {@link Argument}s that would be applied to the selected entity * @param selectionSet The fields of the entity that are selected * * @return a top-level selection * * @see Fields * @see Arguments * @see Object Types and Fields */ public static Selection field(String name, Arguments arguments, SelectionSet... selectionSet) { return new Field(null, name, arguments, relayWrap(Arrays.asList(selectionSet))); } public static Selection field(String alias, String name, Arguments arguments, SelectionSet... selectionSet) { return new Field(alias, name, arguments, relayWrap(Arrays.asList(selectionSet))); } /** * Creates an attribute(scalar field) selection. * * @param name The name of the selected attribute that would appear in a GraphQL query. * * @return a field that represents an non-reltionship entity attribute * * @see Scalar Field */ public static Selection field(String name) { return Field.scalarField(name); } /** * Creates an attribute field selection with arguments. * @param name The name of the field. * @param arguments The arguments. * @return a field that represents an non-reltionship entity attribute */ public static Selection field(String name, Arguments arguments) { return new Field(null, name, arguments, null); } /** * Creates an attribute field selection with arguments and an alias. * @param name The name of the field. * @param alias The alias name of the field. * @param arguments The arguments. * @return a field that represents an non-reltionship entity attribute */ public static Selection field(String name, String alias, Arguments arguments) { return new Field(alias, name, arguments, null); } /** * Creates a complete set of {@link Argument}s that is passed to a object field selection. * * @param arguments A variable-sized group of {@link Argument}s passed to the object field selection * * @return a complete specification of selection arguments * * @see Arguments */ public static Arguments arguments(Argument... arguments) { return new Arguments(Arrays.asList(arguments)); } /** * Creates a {@link Argument single argument} that is passed to a object field selection. * * @param argument The single {@link Argument} passed to the object field selection * * @return a complete specification of selection argument * * @see Arguments */ public static Arguments argument(Argument argument) { return new Arguments(Collections.singletonList(argument)); } /** * Creates a spec object of an GraphQL {@link Argument argument} whose value is not quoted. * * @param name The name of the argument * @param value An object that models argument value. * * @return a complete specification of selection arguments * * @see Arguments */ public static Argument argument(String name, Object value) { return argument(name, value, false); } /** * Creates a spec object of an GraphQL {@link Argument argument}. * * @param name The name of the argument * @param value An object that models argument value. * @param quoted Whether or not the serialized {@code value} should be double-quote * * @return a complete specification of selection arguments * * @see Arguments */ public static Argument argument(String name, Object value, boolean quoted) { if (value instanceof String) { value = quoted ? Field.quoteValue(value.toString()) : value; return new Argument(name, value); } // this is an object which needs to be Jackson-serialized try { return new Argument( name, BASE_MAPPER .configure( // GraphQL argument name is unquoted; hence quoted field is disabled. JsonGenerator.Feature.QUOTE_FIELD_NAMES, false ) .writeValueAsString(value) ); } catch (JsonProcessingException exception) { throw new IllegalStateException(String.format("Cannot serialize %s", value), exception); } } /** * Wraps a set of field selections inside a Relay connection pattern spec. *

* For example, *

     * {@code
     * book(ids: $bookId) {
     *     id
     *     title
     *     authors {
     *         name
     *     }
     * }
     * }
     * 
* becomes *
     * {@code
     * book(ids: $bookId) {
     *     edges {
     *         node {
     *             id
     *             title
     *             authors {
     *                 edges {
     *                     node {
     *                         name
     *                     }
     *                 }
     *             }
     *         }
     *     }
     * }
     * }
     * 
* * @param selectionSet The field selections to be wrapped * * @return the same GraphQL spec in Relay's annotation * * @see Relay's connection pattern */ private static SelectionSet relayWrap(List selectionSet) { Edges edges = new Edges( selectionSet.stream() .map(Node::new) .collect(Collectors.toList()) ); return new SelectionSet(new LinkedHashSet<>(Collections.singleton(edges))); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy