UNPKG

2.79 kBPlain TextView Raw
1import { DocumentNode, FragmentDefinitionNode } from 'graphql';
2import { invariant, InvariantError } from 'ts-invariant';
3
4/**
5 * Returns a query document which adds a single query operation that only
6 * spreads the target fragment inside of it.
7 *
8 * So for example a document of:
9 *
10 * ```graphql
11 * fragment foo on Foo { a b c }
12 * ```
13 *
14 * Turns into:
15 *
16 * ```graphql
17 * { ...foo }
18 *
19 * fragment foo on Foo { a b c }
20 * ```
21 *
22 * The target fragment will either be the only fragment in the document, or a
23 * fragment specified by the provided `fragmentName`. If there is more than one
24 * fragment, but a `fragmentName` was not defined then an error will be thrown.
25 */
26export function getFragmentQueryDocument(
27 document: DocumentNode,
28 fragmentName?: string,
29): DocumentNode {
30 let actualFragmentName = fragmentName;
31
32 // Build an array of all our fragment definitions that will be used for
33 // validations. We also do some validations on the other definitions in the
34 // document while building this list.
35 const fragments: Array<FragmentDefinitionNode> = [];
36 document.definitions.forEach(definition => {
37 // Throw an error if we encounter an operation definition because we will
38 // define our own operation definition later on.
39 if (definition.kind === 'OperationDefinition') {
40 throw new InvariantError(
41 `Found a ${definition.operation} operation${
42 definition.name ? ` named '${definition.name.value}'` : ''
43 }. ` +
44 'No operations are allowed when using a fragment as a query. Only fragments are allowed.',
45 );
46 }
47 // Add our definition to the fragments array if it is a fragment
48 // definition.
49 if (definition.kind === 'FragmentDefinition') {
50 fragments.push(definition);
51 }
52 });
53
54 // If the user did not give us a fragment name then let us try to get a
55 // name from a single fragment in the definition.
56 if (typeof actualFragmentName === 'undefined') {
57 invariant(
58 fragments.length === 1,
59 `Found ${
60 fragments.length
61 } fragments. \`fragmentName\` must be provided when there is not exactly 1 fragment.`,
62 );
63 actualFragmentName = fragments[0].name.value;
64 }
65
66 // Generate a query document with an operation that simply spreads the
67 // fragment inside of it.
68 const query: DocumentNode = {
69 ...document,
70 definitions: [
71 {
72 kind: 'OperationDefinition',
73 operation: 'query',
74 selectionSet: {
75 kind: 'SelectionSet',
76 selections: [
77 {
78 kind: 'FragmentSpread',
79 name: {
80 kind: 'Name',
81 value: actualFragmentName,
82 },
83 },
84 ],
85 },
86 },
87 ...document.definitions,
88 ],
89 };
90
91 return query;
92}