GQLFragment.java

package net.morimekta.providence.graphql.gql;

import net.morimekta.providence.descriptor.PMessageDescriptor;

import javax.annotation.Nonnull;
import java.util.List;

/**
 * A fragment is a piece of a field list representing a single
 * type as part of a struct, union, union list, interface list
 * etc. E.g. consider the graphql type structure:
 *
 * <pre>{@code
 * interface Character {
 *     name: String!
 *     appears_in: [Movie!]!
 * }
 * type Human implements Character {
 *     height: Float!
 * }
 * type Droid implements Character {
 *     purpose: String!
 * }
 * union CharacterUnion = Human | Droid
 * type Query {
 *   hero: CharacterUnion
 * }
 * }</pre>
 *
 * And the query document:
 *
 * <pre>{@code
 * {
 *     hero {
 *         name
 *         ... on Droid {
 *             purpose
 *         }
 *         ... HumanFields
 *     }
 * }
 *
 * fragment HumanFields on Human {
 *     height
 * }
 * }</pre>
 *
 * Here <code>...of Droid</code> is an inline fragment, and
 * <code>HumanFields</code> is a fragment reference and definition.
 */
public interface GQLFragment extends GQLSelection {
    /**
     * All fragments represent a specific message type of a union
     * field, or an interface implementation. This should return
     * the descriptor of that message type.
     *
     * @return The fragment type descriptor.
     */
    @Nonnull
    PMessageDescriptor<?> getTypeCondition();

    @Nonnull
    @Override
    List<GQLSelection> getSelectionSet();

    /**
     * @param containingType Containing type to check.
     * @return True if the fragment should be applied when writing content for the
     *         containing message type.
     */
    default boolean isApplicableFor(PMessageDescriptor<?> containingType) {
        PMessageDescriptor<?> cond = getTypeCondition();
        return (cond.equals(containingType) ||
                cond.equals(containingType.getImplementing()));
    }
}