Git Product home page Git Product logo

graphql-combine-query's Introduction

graphql-combine-query

Build Status

This is a util to combine multiple graphql queries or mutations into a single one.

Why?

  • There are situations where you do not know ahead of time what fields will need to be invoked with a mutation, so cannot prepate a single graphql document ahead of time
  • Some graphql servers, like Hasura will execute each mutation in a single database transaction, which is desirable for changes being made
  • It just might be easier to deal with state of a single query/mutation compared to making several calls to backend

Install

npm install graphql-combine-query

Usage / examples

combine several queries / mutations together

create query builder with combineQuery(newQueryName) and use .add(document, variables) to add queries to it. argument list & top level selections are concatenated

import combineQuery from 'graphql-combine-query'

import gql from 'graphql-tag'

const fooQuery = gql`
  query FooQuery($foo: String!) {
    getFoo(foo: $foo)
  }
`

const barQuery = gql`
  query BarQuery($bar: String!) {
    getBar(bar: $bar)
  }
`

const { document, variables } = combineQuery('FooBarQuery')
  .add(fooQuery, { foo: 'some value' })
  .add(barQuery, { bar: 'another value' })

console.log(variables)
// { foo: 'some value', bar: 'another value' }

print(document)
/*
query FooBarQuery($foo: String!, $bar: String!) {
   getFoo(foo: $foo)
   getBar(bar: $bar)
}
*/

add multiple instances of the same query / mutation

It's not uncommon to need to add the same mutation several times, eg when updating multiple objects. In this case use addN(document, variables[]) Arguments & top level selections will be renamed/aliased with index appended.

Let's say we want to create foo and update several bars by id:

import combineQuery from 'graphql-combine-query'

import gql from 'graphql-tag'

const createFooMutation = gql`
  mutation CreateFoo($foo: foo_input!) {
    createFoo(foo: $foo) {
      id
    }
  }
`

const updateBarMutation = gql`
  mutation UpdateBar($bar_id: Int!, $bar: bar_update_input!) {
    updateBar(where: { id: { _eq: $bar_id } }, _set: $bar) {
      id
    }
  }
`

const { document, variables } = (() => combineQuery('CompositeMutation')
  .add(createFooMutation, { foo: { name: 'A foo' }})
  .addN(updateBarMutation, [
    { bar_id: 1, bar: { name: 'Some bar' }},
    { bar_id: 2, bar: { name: 'Another bar' }}
  ])
)()

console.log(variables)
/*
{
  foo: { name: 'A foo' },
  bar_id_0: 1,
  bar_0: { name: 'Some bar' },
  bar_id_1: 2,
  bar_1: { name: 'Another bar' }
}

*/

print(document)

/*
mutation CompositeMutation($foo: foo_input!, $bar_id_0: Int!, $bar_0: bar_update_input!, $bar_id_1: Int!, $bar_1: bar_update_input!) {
    createFoo(foo: $foo) {
      id
    }
    updateBar_0: updateBar(where: {id: {_eq: $bar_id_0}}, _set: $bar_0) {
      id
    }
    updateBar_1: updateBar(where: {id: {_eq: $bar_id_1}}, _set: $bar_1) {
      id
    }
  } 
*/

graphql-combine-query's People

Contributors

dependabot[bot] avatar domasx2 avatar fedeya avatar kinow avatar mihaerzen avatar tsiege avatar xandmore avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

graphql-combine-query's Issues

Installing this library causes errors when compiling

This is the error i am getting

node_modules/graphql-combine-query/dist/index.d.ts:6:136 - error TS2344: Type 'TVariables' does not satisfy the constraint 'OperationVariables'.

6     add: <TData = any, TVariables = OperationVariables>(document: DocumentNode, variables?: TVariables) => CombinedQueryBuilder<TData, TVariables>;
                                                                                                                                         ~~~~~~~~~~

  node_modules/graphql-combine-query/dist/index.d.ts:6:24
    6     add: <TData = any, TVariables = OperationVariables>(document: DocumentNode, variables?: TVariables) => CombinedQueryBuilder<TData, TVariables>;
                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    This type parameter might need an `extends OperationVariables` constraint.


Found 1 error in node_modules/graphql-combine-query/dist/index.d.ts:6

Here is my tsconfig

{
	"compilerOptions": {
		"rootDirs": ["src"],
		"outDir": "dist",
		"lib": ["es2020"],
		"target": "es2020",
		"module": "esnext",
		"moduleResolution": "node",
		"types": ["node", "jest"],
		"resolveJsonModule": true,
		"esModuleInterop": true,
		"strictNullChecks": true,
		"experimentalDecorators": true
	},
	"exclude": [
		"node_modules",
		"dist",
		"jest.config.ts",
		"src/tests/*",
		"jest-setup.ts"
	]
}

I am using node18

browser usage

For browser usage what would be the equivalent of print() for retrieving the combined literal for posting to the graphQL server?

initial empty query ? + node_module warning

I am generating forms based on a config (object) and some of the inputs would have queries in them to display foreign data in the dropdown menu inputs

so I have a loop that finds the inputs that need foreign data and I merge them into one final query, however there will be
an arbitrary initial query schema that I need to use to make it work, since I can't merge it with an initial empty schema.

in this case the companiesQuery is the initial schema

let companiesQuery = gql`query { companies { id: company_id, company_name } }`

let finalSchema = companiesQuery   // need arbitrary schema so first merge will work

config.formFields.forEach(each => {
	if (each.foreignQuery) { 
		const { document } = combineQuery('CombinedQuery').add(finalSchema).add(each.foreignQuery)
		finalSchema = document
	 }
})

this works perfectly fine but it would be nice not to have an extra call somehow because its causing me other problems other than using extra resources.

I understand if this isn't the scope of the library. But there is one more thing which I wanted to mention, with the code above, it does work perfectly fine but I am getting warnings which I would like to get rid of

WARNING in ./node_modules/graphql-combine-query/dist/index.js
Module Warning (from ./node_modules/source-map-loader/dist/cjs.js):
Failed to parse source map from 'C:\Users\<retracted>\<retracted>\<retracted>\frontend\node_modules\graphql-combine-query\src\index.ts' file: Error: ENOENT: no such file or directory, open 'C:\Users\<retracted>\<retracted>\<retracted>\frontend\node_modules\graphql-combine-query\src\index.ts'

let me know if you need extra info, and thanks a ton for this library!

Error : TypeError: combineQuery is not a function

I try to use it with default example and nodejs but I got this strange error ...

>node graphql-combine-query_test_001.mjs
file:///E:/testgithubgraphql/graphql-combine-query_test_001.mjs:20
const { document, variables } = combineQuery('FooBarQuery')
                                ^
TypeError: combineQuery is not a function
    at file:///E:/testgithubgraphql/graphql-combine-query_test_001.mjs:20:33
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:526:24)
    at async loadESM (node:internal/process/esm_loader:91:5)
    at async handleMainPromise (node:internal/modules/run_main:65:12)

dist version

Can we have a dist version (js) ?

Thanks in advance !

Overlapping queries / Duplicate top-level fields not allowed?

Hi There,

I followed this Stack Overflow link here as I want to do exactly the same as the author of that question:

but when I try to implement his example it fails for me with a duplicate field definition post for oprations Query1 and Query2 error:

tap.test('queries can be combined', (test) => {
  // given
  const query1 = gql`
    query Query1 {
      post(id: 1234) {
        title
        description
      }
    }
  `
  const query2 = gql`
    query Query2 {
      post(id: 1234) {
        tags
        author {
          name
        }
      }
    }
  `
  const { document } = combineQuery('CombinedQuery').add(query1).add(query2)

  // then
  test.equals(
    print(document),
    print(gql`
      query CombinedQuery {
        post(id: 1234) {
          title
          description
          tags
          author {
            name
          }
        }
      }
    `)
  )
  test.end()
})

I realise that you have some fancy logic for merging query variables which may have something to do with why you have this top-level restriction, or is this something that can be relaxed so you can also support merging of overlapping queries (without having to use fragments of course)?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.