Search code examples
javascriptnode.jstypescriptgraphqlapollo

GraphQL Dynamically build fragment from array


Following other answers, it seems that the recommended way of building dynamic query is to use fragments in this manner:

const series1Q = gql`
  fragment series1 on timeseriesDataQuery {
    series1: timeseriesData(sourceId: "source1") {
      data {
        time
        value
      }
    }
  }
}

const series2Q = gql`
  fragment series2 on timeseriesDataQuery {
    series2: timeseriesData(sourceId: "source2") {
      data {
        time
        value
      }
    }
  }
}

And joining them with:

export const mainQuery = gql`
    query fetchData {
      ...series1 
      ...series2
    }
    ${series1Q}
    ${series2Q}
`  

However in my case, I do not know the number of items as the user can add a number of item to it so I end up with an array eg,

const series = 
[
    gql`
        fragment series1 on timeseriesDataQuery {
            series1: timeseriesData(sourceId: "source1") {
                data {
                    time
                    value
                }
            }
        }
    `,
    gql`
        fragment series2 on timeseriesDataQuery {
            series2: timeseriesData(sourceId: "source2") {
                data {
                    time
                    value
                }
            }
        }
    `
]

I cant seem to join them in the gql func, have tried different ways eg,

export const mainQuery = gql`
    ${...series}
    query fetchData {
      ...series1 
      ...series2
    }
`  

or

export const mainQuery = gql`
    {...series}
    query fetchData {
      ...series1 
      ...series2
    }
`  

and all seems to be in the wrong format,

CodeSandbox: https://codesandbox.io/s/compassionate-germain-hs16ti?file=/src/App.tsx

Have anyone managed to create a dynamic query from array?


Solution

  • So I think the main issue was with the fragment piece being parsed to [object Object] when using the map func: ${query.sql} or other equivalent,

    A workaround was to get the fragment query using query.sql.loc.source.body

    Example of a working example using @Dakeyras answer:

    const series = 
    [{
        name: 'series1',
        sql: gql`
            fragment series1 on timeseriesDataQuery {
                series1: timeseriesData(sourceId: "source1") {
                    data {
                        time
                        value
                    }
                }
            }
        `,
    },
    {
        name: 'series2',
        sql: gql`
            fragment series2 on timeseriesDataQuery {
                series2: timeseriesData(sourceId: "source2") {
                    data {
                        time
                        value
                    }
                }
            }
        `
    }]
    
    export const mainQuery = gql`
        query fetchData {
          ${series.map(query => `...${query.name}`).join('\n')}
        }
        ${series.map(query => `${query.sql.loc?.source.body}`).join('\n')}
    `