Passing array of fragments to query fails, e.g.:
query SomeQuery {
field {
someRuntimeGeneratedFieldsOnFragments
}
}
${arrayOfFragments}
with error
Syntax Error GraphQL (25:1) Unexpected [
24: }
25: [object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
^
26:
It is working as expected when using createFragments + fragments option in apollo-client, which is being deprecated in next version.
How are you creating the array of fragments? Perhaps there is a way to do it via interpolation.
It is just an array of fragments generated by gql tagged string, e.g.
arrayOfFragments = [gql`frag1...`, gql`frag2...`]
In my use case, array is generated dynamically on js load time, based on registered child's component fragments, e.g.
const registeredComponents = [Component1, Component2, ...];
const arrayOfFragments = registeredComponents.map(c => c.fragments.someFragment)
Explicitly enumerating over array in gql is a possible workaround, however not the most elegant...
query SomeQuery {
field {
someRuntimeGeneratedFieldsOnFragments
}
}
${arrayOfFragments[0]}
${arrayOfFragments[1]}
...
Should we add in special support for this? I'm not sure if it's a common enough thing to make it worth it.
For now, I just wrapped gql into custom gql tag literal, that expands arrays prior to passing it to gql, i.e.
import origGql from 'graphql-tag';
export default function(literals, ...args) {
const newLiterals = [literals[0]];
const newArgs = [];
args.forEach((arg, i) => {
if (Array.isArray(arg)) {
newArgs.push(...arg);
if (arg.length > 0) {
const filler = Array(arg.length - 1).fill('');
newLiterals.push(...filler);
newLiterals.push(literals[i + 1]);
}
} else {
newLiterals.push(literals[i + 1]);
newArgs.push(arg);
}
});
return origGql(newLiterals, ...newArgs);
}
This works just fine for my use case, so if this functionality is considered too specific to be included in graphql-tag, issue can be closed as far as I am concerned...
i think there is _some_ use case for being able to pass both an array of fragments or map whose values are fragments (as those are often how our components are storing references to the fragments), but there hasn't been so much pain in just being explicit about what fragments are being interpolated. closing this for now.
Figured out another hacky way of doing this :
Helper function to combine multiple fragments body string into single string.
// pivotFragments combine fragments template string into a single string.
const pivotFragments = (fragments) => {
if (Array.isArray(fragments) && fragments.length > 0) {
return fragments.reduce((result, fragment, idx) => {
let output = result;
const { loc: { source: { body } } } = fragment;
if (idx === 0) {
output = body;
return output;
}
return `${output}${body}`;
}, '');
}
return '';
};
Then in your GraphQL schema :
const generateSchema = (fragments) => {
const fs = pivotFragments(fragments);
return gql`
query MyQuery {
user {...BarFields}
income {...FooFields}
}
${fs}
`;
};
const schema = generateSchema([
gql`
fragment FooFields on Foo {
id
field
}
`,
gql`
fragment BarFields on Bar {
id
field
}
`,
...
// will be parsed as following
return gql`
query MyQuery {
user {...BarFields}
income {...FooFields}
}
fragment FooFields on Foo {
id
field
}
fragment BarFields on Bar {
id
field
}
`;
])
Basically you extract the fragment string literal and insert them back to your gql tag and let the parser do the rest
found a way to insert an array of fragments into query by combining them into a single gql-tag:
gql`
query {
...fragment1
...fragment2
}
${fragments.reduce((acc, fragment) => gql`
${acc}
${fragment}
`, '')}
`
Most helpful comment
found a way to insert an array of fragments into query by combining them into a single gql-tag: