Giter Site home page Giter Site logo

atulmy / gql-query-builder Goto Github PK

View Code? Open in Web Editor NEW
388.0 5.0 42.0 742 KB

🔧 Simple GraphQL Query Builder

Home Page: https://npmjs.com/package/gql-query-builder

License: MIT License

TypeScript 99.71% Shell 0.29%
graphql nodejs query-builder generator query-generator

gql-query-builder's Introduction

gql-query-builder's People

Contributors

airhorns avatar arhariri avatar atulmy avatar bebraw avatar cbonaudo avatar ccollie avatar clement-berard avatar comlock avatar danielhreben avatar devorein avatar joaopedroas51 avatar leeroyrose avatar mdowds avatar platformjb avatar rcc913 avatar scott-rc avatar t2y avatar themagickoala avatar toadkicker 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

gql-query-builder's Issues

mutation - variable with null value

consider this code server-side

type Mutation {
  updateMessage(id: Number!, text: String): Boolean
}

and this code client-side

const mutation = gql.mutation({
    operation: 'updateMessage',
    variables: {
        id: {value: 1, required: true},
        text: null
  }
})

now if you print out the mutation, text variable has Object type

console.log(mutation);

//query
mutation ($id: Int!, $text: Object) {
  updateMessage (id: $id, text: $text) 
}

//variables
{
    id: 1,
    text: null
}

the reason is obvious, gql-query-builder cannot determine the type when just null is provided - it might be any type.


if you send this mutation to the server-side, in response you get error

message: "Unknown type "Object"."

server-side does not know type Object; moreover the type coming from client-side (infered by gql-query-builder) has to correspond with the type defined on server-side (in graphql schema)


by now, i use workaround by specifing the variable type explicitly

const mutation = gql.mutation({
    operation: 'updateMessage',
    variables: {
        id: {value: 1, required: true},
        text: {value: null, type: "String"}
  }
})

is this workaround alright or is there a better way?
i cannot think of any other ways, as it is impossible to know the intended type when just null is provided.

thanks in advance!

v3.5.2 npm broken (probably due to npm-publish.yml)

Hey @atulmy,

I'm not sure why or how, but something is really broken in the v3.5.2 package published on npm.
Just try npm i gql-query-builder or yarn add gql-query-builder in an empty project and you'll see the only files you end up with in node_modules/gql-query-builder are these:

-rw-r--r-- 1 user user 1.1K Dec  5 12:49 LICENSE
-rw-r--r-- 1 user user  13K Dec  5 12:49 README.md
-rw-r--r-- 1 user user 1.5K Dec  5 12:49 package.json

There must be something wrong with your npm-publish.yml workflow.
Let me know if there's anything I can do to help.

[suggestion] type for variables

variables should have a type, it is well defined in the README but uses any.

My suggestion:

type Value = string | number | boolean | Record<string, any>;

interface Variables {
  value: Value;
  type?: string;
  required?: true;
}

type VariablesRecord<T extends Record<string, any> = Record<string, any>> = Record<keyof T, Variables>;

and query<T>() mutate<T>() etc

Custom mutation addapter type error when in strict mode

After creating a custom mutation adapter it throws an error when I pass it's type on mutation function.
In order to check if the problem was related with my adapter code I tried to pass the default mutation adapter directly and the same error occurs.

Steps to reproduce:

  1. Setup an angular v13 solution (using typescript strict mode)
  2. Execute the mutation function passing DefaultMutationAdapter type as parameter
  3. The error is thrown: Argument of type 'typeof DefaultMutationAdapter' is not assignable to parameter of type 'IMutationAdapter'. Type 'typeof DefaultMutationAdapter' is missing the following properties from type 'IMutationAdapter': mutationBuilder, mutationsBuilder'. Type 'IMutationAdapter' is missing the following properties from type 'IMutationAdapter': mutationBuilder, mutationsBuilder

Example:
`
import * as gql from 'gql-query-builder';
import DefaultMutationAdapter from 'gql-query-builder/build/adapters/DefaultMutationAdapter';

const query = gql.mutation({
operation: 'thoughtCreate',
variables: {
name: 'Tyrion Lannister',
thought: 'I drink and I know things.'
},
fields: ['id']
}, DefaultMutationAdapter);

console.log(query);

// Output
mutation ($name: String, $thought: String) {
thoughtCreate (name: $name, thought: $thought) {
id
}
}

// Variables
{
"name": "Tyrion Lannister",
"thought": "I drink and I know things."
}
`

Error with queryBuilder : mutation is not a function

Hi,

I have this following code :


import {Component, OnInit} from '@angular/core';
import {MaerdoBaseAdminComponent} from "../maerdo-core/_helpers/MaerdoBaseAdminComponent.class";
import {Apollo} from 'apollo-angular';
import * as builder from 'gql-query-builder'

@Component({
  selector: 'maerdo-admin-modules-create',
  templateUrl: './maerdo-admin-modules-create.component.html',
  styleUrls: ['./maerdo-admin-modules-create.component.scss']
})
export class MaerdoAdminModulesCreateComponent extends MaerdoBaseAdminComponent implements OnInit {

  protected moduleEntity = {
    "name": "rezrez",
    "slug": "rezrze",
    "desc_fr": "rezrez",
    "desc_en": "rzerez",
    "desc_es": "rezrez"
  };

  constructor(protected apollo: Apollo) {
    super();
  }

  ngOnInit() {
  }

  nameToSlug() {
    this.moduleEntity.slug = this.toSlug(this.moduleEntity.name);
  }

  screenshotUploader(event) {

  }

  createModule() {

    const createModuleQuery = builder.mutation({
      operation: 'createModule',
      variables: this.moduleEntity,
      fields: ['id','name','slug']
    });
    console.log(createModuleQuery);
    this.update(createModuleQuery, "moduleEntity", this);
  }

}

And when i try to call builder.mutation i have this error msg :


MaerdoAdminModulesCreateComponent.html:37 ERROR TypeError: builder.mutation is not a function
    at MaerdoAdminModulesCreateComponent.push../src/app/maerdo-admin-modules-create/maerdo-admin-modules-create.component.ts.MaerdoAdminModulesCreateComponent.createModule (maerdo-admin-modules-create.component.ts:38)
    at Object.eval [as handleEvent] (MaerdoAdminModulesCreateComponent.html:37)
    at handleEvent (core.js:23106)
    at callWithDebugContext (core.js:24176)
    at Object.debugHandleEvent [as handleEvent] (core.js:23903)
    at dispatchEvent (core.js:20555)
    at core.js:21002
    at HTMLButtonElement.<anonymous> (platform-browser.js:993)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:17289)
View_MaerdoAdminModulesCreateComponent_0 @ MaerdoAdminModulesCreateComponent.html:37
proxyClass @ compiler.js:18239
push../node_modules/@angular/core/fesm5/core.js.DebugContext_.logError @ core.js:24138
push../node_modules/@angular/core/fesm5/core.js.ErrorHandler.handleError @ core.js:15771
dispatchEvent @ core.js:20559
(anonymous) @ core.js:21002
(anonymous) @ platform-browser.js:993
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
onInvokeTask @ core.js:17289
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:422
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:498
invokeTask @ zone.js:1744
globalZoneAwareCallback @ zone.js:1770
MaerdoAdminModulesCreateComponent.html:37 ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 71, nodeDef: {…}, elDef: {…}, elView: {…}}

Attempting multiple queries with the same variable name does not work as expected

I'm attempting a fairly simple multi-query where I want to retrieve multiple counts from a single request with varying values. (i.e. get the count of fruit for several different statuses)

Given the example query below:

[
    {
        "operation": "statusId1: fruit",
        "variables": {
            "fruit_id": {
                "required": true,
                "value": 36
            },
            "where": {
                "type": "QueryFruitWhereConditions",
                "value": {
                    "AND": [
                        {
                            "column": "status_id",
                            "operator": "EQ",
                            "value": 1
                        }
                    ]
                }
            }
        },
        "fields": [
            {
                "meta": [
                    "total"
                ]
            }
        ]
    },
    {
        "operation": "statusId2: fruit",
        "variables": {
            "fruit_id": {
                "required": true,
                "value": 36
            },
            "where": {
                "type": "QueryFruitWhereConditions",
                "value": {
                    "AND": [
                        {
                            "column": "status_id",
                            "operator": "EQ",
                            "value": 2
                        }
                    ]
                }
            }
        },
        "fields": [
            {
                "meta": [
                    "total"
                ]
            }
        ]
    }
]

The following query will be built out:

{
    "query": "query ($fruit_id: Int!, $where: QueryFruitWhereConditions) { statusId1: fruit (fruit_id: $fruit_id, where: $where) { meta { total } } statusId2: fruit (fruit_id: $fruit_id, where: $where) { meta { total } } }",
    "variables": {
        "fruit_id": 36,
        "where": {
            "AND": [
                {
                    "column": "status_id",
                    "operator": "EQ",
                    "value": 2
                }
            ]
        }
    }
}

This is an issue because the where variable is intentionally different between queries; however, the last query's value for the variable is used for the entire query set. Is this a bug or is there some sort of workaround I could do?

Mutation is working fine but when try to use query it does not returns the data instead shows api failure message.

Code : const getTopPostsByGroupIdQuery = query({
operation: getTopPostsByGroupId,
variables: {
groupId: {value: 3d42529f-e129-4e8f-87a8-e53a0a0fccbe, required: true},
postType: {value: Text, required: true},
limit: {value: 10, required: true},
startMonth: {value: 10, required: true},
endMonth: {value: 10, required: true},
startYear: {value: 2019, required: true},
endYear: {value: 2020, required: true}
},
fields: [activityRate, postCreatedAtUTC, commentCount]
cy.api({
method: POST,
url: appSyncUrl,
headers: {
authorization:noGroupAdminAuth
},
body: getTopPostsByGroupIdQuery
}).then(({body}) => {
const {
data: {getTopPostsByGroupId},
errors: [{errorType, message}]
} = body;
Can you please check if anything is missing in above code.

Fields data object

I try to send de query but send me an error

Query:
{
metrics {
id
name
paginatorInfo{
count
currentPage
firstItem
hasMorePages
lastItem
lastPage
perPage
total
}
}
}

image

Correct query:
{
metrics {
data {
id
name
}
paginatorInfo{
count
currentPage
firstItem
hasMorePages
lastItem
lastPage
perPage
total
}
}
}
Need put fields into object named "data {}", how can make if??

image

Add ability to add argument names of a variable

For example:-

const gqlquery = query([
	{
		operation: 'someoperation',
		fields: [
			{
				operation: 'nestedoperation',
				fields: [],
				variables: {
					id2: {
						type: 'ID',
						value: 123
					}
				}
			}
		],
		variables: {
			id1: {
				type: 'ID',
				value: 456
			}
		}
	}
]);

// Output

query ($id2: ID, $id1: ID) { someoperation (id1: $id1) { nestedoperation (id2: $id2) {  } } }

Maybe add the ability in the variable definition to add a name property to change the argument name

const gqlquery = query([
	{
		operation: 'someoperation',
		fields: [
			{
				operation: 'nestedoperation',
				fields: [],
				variables: {
					id2: {
						type: 'ID',
						value: 123,
						name: 'id'
					}
				}
			}
		],
		variables: {
			id1: {
				type: 'ID',
				value: 456,
				name: 'id'
			}
		}
	}
]);

// Output

query ($id2: ID, $id1: ID) { someoperation (id: $id1) { nestedoperation (id: $id2) {  } } }

By default it could be the keyname but, I think adding the ability to separate the argument name and variable name could be helpful in some instances. Let me try to submit a PR resolving this issue

Multiple query variables doesn't get set in the root query

PR#35 did solve the issue on nested fields, but unfortunately when using multiple operations the problem persists.

For example for the below query ...

const gqlquery = query([
  {
    operation: "getPublicationCount",
    variables: {
      round: true
    }
  },
  {
    operation: "getPublicationCount",
    variables: {
      ceil: true
    }
  }
]);

gqlquery.query is ...

query ($ceil: Boolean) { getPublicationCount (round: $round) { } getPublicationCount (ceil: $ceil) { } }

But it should be

query ($round: Boolean, $ceil: Boolean) { getPublicationCount (round: $round) getPublicationCount (ceil: $ceil) }

My PR solves the case with extraneous brackets but, it seems only the latest variables are set at the root query operation.

support for union types

is there support for unions and/or interfaces? one of my api calls returns content and content is a union type that can return diff types of models.

Example desired query output:

{
  vehicle {
     ... on Car {
       name
       isSedan
       NumSeats
       topSpeed
     }

     ... on Scooter {
       name
       isElectric
       numMiles
       topSpeed
    }
  }
}

should check required type

when build a query
should be able to check required type

 mutation Login($email: String!, $password:String!){
        Login(email:$email, password: $password){
            success
            error
            token
  }
}

Allow naming mutations

The gql.query function takes an optional config object in which I can pass an operationName to name my query. This makes testing queries against a mock GQL server using MSW very easy as I can configure it to respond to incoming queries by the operationName https://mswjs.io/docs/getting-started/mocks/graphql-api#request-handler

The gql.mutation function doesn't take this config object so I can't easily name mutations. This makes testing them with MSW much harder as I have to separately parse the GQL into an AST and locate the name of the underlying mutation that is called.

Could you add this config object to gql-query-builder?

Custom types

Hello!

I'm using the Crate application and it is really good as a starting point for new projects! So thanks for that 😊

In the Crate code for the API part, I wanted to create a new custom type for my query. But it seems that gql-query-builder does not support custom types yet.

I wanted to get this working right now so I did the following not so good looking change in the queryDataType function 😑

// Get GraphQL equivalent type of data passed (String, Int, Float, Boolean)
function queryDataType(variable: any) {
  let type = "String";

  const value = typeof variable === "object" ? variable.value : variable;

  if (variable.type !== undefined) {
    type = variable.type;
  } else {
    switch (typeof value) {
      case "object":
        type = "Object";
        break;

      case "boolean":
        type = "Boolean";
        break;

      case "number":
        type = value % 1 === 0 ? "Int" : "Float";
        break;
    }
  }

  if (typeof variable === "object" && variable.required) {
    type += "!";
  }

  return type;
}

As you can see, I only added a variable.type check/assing for now to make it work.
Is this something you would consider adding to this lib?

query with empty fields will build a wrong Syntax

for example

const query = {
    operation,
    variables: {
      id: {
        value: id,
        type: 'String!',
      },
      uid: {
        value: uid,
        type: 'Int!',
      },
      key: {
        value: key,
        type: 'String',
      }
    },
    fields // this is undefined
  }

//output

query: "query ($id: String!, $uid: Int!, $key: String) { a…orize_info (id: $id, uid: $uid, key: $key) **{  }**"

Published npm version should contain src folder

Hello. First of all thanks for great tool!

I updated my app to webpack 5 and it got smarter :)

For now I receive warnings that webpack can't find source maps for gql-query-builder

Failed to parse source map from '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/NestedField.ts' file: Error: ENOENT: no such file or directory, open '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/NestedField.ts'

Failed to parse source map from '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/OperationType.ts' file: Error: ENOENT: no such file or directory, open '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/OperationType.ts'

Failed to parse source map from '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/Utils.ts' file: Error: ENOENT: no such file or directory, open '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/Utils.ts'

Failed to parse source map from '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/DefaultAppSyncMutationAdapter.ts' file: Error: ENOENT: no such file or directory, open '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/DefaultAppSyncMutationAdapter.ts'

Failed to parse source map from '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/DefaultAppSyncQueryAdapter.ts' file: Error: ENOENT: no such file or directory, open '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/DefaultAppSyncQueryAdapter.ts'

Failed to parse source map from '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/DefaultMutationAdapter.ts' file: Error: ENOENT: no such file or directory, open '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/DefaultMutationAdapter.ts'

Failed to parse source map from '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/DefaultQueryAdapter.ts' file: Error: ENOENT: no such file or directory, open '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/DefaultQueryAdapter.ts'

Failed to parse source map from '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/DefaultSubscriptionAdapter.ts' file: Error: ENOENT: no such file or directory, open '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/DefaultSubscriptionAdapter.ts'

Failed to parse source map from '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/index.ts' file: Error: ENOENT: no such file or directory, open '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/adapters/index.ts'

Failed to parse source map from '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/index.ts' file: Error: ENOENT: no such file or directory, open '/home/eugene/projects/front-tm2/node_modules/gql-query-builder/src/index.ts'

And, for example node_modules/gql_query_builder/build/Fields.js.map has this code

{"version":3,"file":"Fields.js","sourceRoot":"","sources":["../src/Fields.ts"],"names":[],"mappings":""}

"sources":["../src/Fields.ts"] points to a non-existent file

Relay Input support

Hi,
could you please add relay input support?
Sample mutation query:

mutation categoriesUpdate($input: CategoriesUpdateInput!) {
        categoriesUpdate(input: $input) {
            category { id }
            errors
        }
    }

Regards!

Paginate

How do to use pagination into query??

image

How to merge queries?

Let's assume:

i have query:

    gql.query({
        operation: 'user',
        fields: ['name'],
    });

and one more:

    gql.query({
        operation: 'profile',
        fields: ['id', 'photo'],
    });

Everything is nice now.

But what if i need to get both user and profile in one query? What should I do? Is there mechanism to merge these queries. Especially, due to the fact, that one of the best features of GraphQL (comparing with REST) is to combine queries into one.

The 3.1.0 release's build is missing exports

Hello,

I was testing today and it seems like there is a difference between the builds from my local build output and what was in the 3.1.0 npm package. It's like it wasn't built before being published? I don't know.

1a2,12
> var __assign = (this && this.__assign) || function () {
>     __assign = Object.assign || function(t) {
>         for (var s, i = 1, n = arguments.length; i < n; i++) {
>             s = arguments[i];
>             for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
>                 t[p] = s[p];
>         }
>         return t;
>     };
>     return __assign.apply(this, arguments);
> };
3,9c14,19
< var adapters_1 = require("./adapters");
< exports.adapters = adapters_1.default;
< var DefaultMutationAdapter_1 = require("./adapters/DefaultMutationAdapter");
< var DefaultQueryAdapter_1 = require("./adapters/DefaultQueryAdapter");
< var DefaultSubscriptionAdapter_1 = require("./adapters/DefaultSubscriptionAdapter");
< function queryOperation(options, adapter) {
<     var defaultAdapter;
---
> var OperationType;
> (function (OperationType) {
>     OperationType["Mutation"] = "mutation";
>     OperationType["Query"] = "query";
> })(OperationType || (OperationType = {}));
> function queryOperation(options) {
11,20c21
<         if (adapter) {
<             var customAdapter = new adapter(options);
<             return customAdapter.queriesBuilder(options);
<         }
<         defaultAdapter = new DefaultQueryAdapter_1.default(options);
<         return defaultAdapter.queriesBuilder(options);
<     }
<     if (adapter) {
<         var customAdapter = new adapter(options);
<         return customAdapter.queryBuilder();
---
>         return queriesBuilder(options);
22,23c23
<     defaultAdapter = new DefaultQueryAdapter_1.default(options);
<     return defaultAdapter.queryBuilder();
---
>     return queryBuilder(options);
26,28c26,33
< function mutationOperation(options, adapter) {
<     var customAdapter;
<     var defaultAdapter;
---
> function queryBuilder(_a) {
>     var operation = _a.operation, _b = _a.fields, fields = _b === void 0 ? [] : _b, _c = _a.variables, variables = _c === void 0 ? {} : _c;
>     return operationWrapperTemplate(OperationType.Query, variables, operationTemplate({ variables: variables, operation: operation, fields: fields }));
> }
> function queriesBuilder(queries) {
>     return operationWrapperTemplate(OperationType.Query, resolveVariables(queries), queries.map(operationTemplate).join("\n  "));
> }
> function mutationOperation(options) {
30,41c35
<         if (adapter) {
<             // @ts-ignore
<             customAdapter = new adapter(options);
<             return customAdapter.mutationsBuilder(options);
<         }
<         defaultAdapter = new DefaultMutationAdapter_1.default(options);
<         return defaultAdapter.mutationsBuilder(options);
<     }
<     if (adapter) {
<         // @ts-ignore
<         customAdapter = new adapter(options);
<         return customAdapter.mutationBuilder();
---
>         return mutationsBuilder(options);
43,44c37
<     defaultAdapter = new DefaultMutationAdapter_1.default(options);
<     return defaultAdapter.mutationBuilder();
---
>     return mutationBuilder(options);
47,54c40,123
< function subscriptionOperation(options, adapter) {
<     var customAdapter;
<     var defaultAdapter;
<     if (Array.isArray(options)) {
<         if (adapter) {
<             // @ts-ignore
<             customAdapter = new adapter(options);
<             return customAdapter.subscriptionsBuilder(options);
---
> function mutationBuilder(_a) {
>     var operation = _a.operation, _b = _a.fields, fields = _b === void 0 ? [] : _b, _c = _a.variables, variables = _c === void 0 ? {} : _c;
>     return operationWrapperTemplate(OperationType.Mutation, variables, operationTemplate({ variables: variables, operation: operation, fields: fields }));
> }
> function mutationsBuilder(mutations) {
>     return operationWrapperTemplate(OperationType.Mutation, resolveVariables(mutations), mutations.map(operationTemplate).join("\n  "));
> }
> function resolveVariables(operations) {
>     var ret = {};
>     operations.forEach(function (_a) {
>         var variables = _a.variables;
>         ret = __assign({}, ret, variables);
>     });
>     return ret;
> }
> function operationWrapperTemplate(type, variables, content) {
>     return {
>         query: type + " " + queryDataArgumentAndTypeMap(variables) + " {\n  " + content + "\n}",
>         variables: queryVariablesMap(variables)
>     };
> }
> function operationTemplate(_a) {
>     var variables = _a.variables, operation = _a.operation, fields = _a.fields;
>     return operation + " " + queryDataNameAndArgumentMap(variables) + " " + (fields && fields.length > 0
>         ? "{\n    " + queryFieldsMap(fields) + "\n  }"
>         : "");
> }
> // Convert object to name and argument map. eg: (id: $id)
> function queryDataNameAndArgumentMap(variables) {
>     return variables && Object.keys(variables).length
>         ? "(" + Object.keys(variables).reduce(function (dataString, key, i) {
>             return "" + dataString + (i !== 0 ? ", " : "") + key + ": $" + key;
>         }, "") + ")"
>         : "";
> }
> // Convert object to argument and type map. eg: ($id: Int)
> function queryDataArgumentAndTypeMap(variables) {
>     return Object.keys(variables).length
>         ? "(" + Object.keys(variables).reduce(function (dataString, key, i) {
>             return "" + dataString + (i !== 0 ? ", " : "") + "$" + key + ": " + queryDataType(variables[key]);
>         }, "") + ")"
>         : "";
> }
> // Fields selection map. eg: { id, name }
> function queryFieldsMap(fields) {
>     return fields
>         ? fields
>             .map(function (field) {
>             return typeof field === "object"
>                 ? Object.keys(field)[0] + " { " + queryFieldsMap(Object.values(field)[0]) + " }"
>                 : "" + field;
>         })
>             .join(", ")
>         : "";
> }
> // Variables map. eg: { "id": 1, "name": "Jon Doe" }
> function queryVariablesMap(variables) {
>     var variablesMapped = {};
>     Object.keys(variables).map(function (key) {
>         variablesMapped[key] =
>             typeof variables[key] === "object"
>                 ? variables[key].value
>                 : variables[key];
>     });
>     return variablesMapped;
> }
> // Get GraphQL equivalent type of data passed (String, Int, Float, Boolean)
> function queryDataType(variable) {
>     var type = "String";
>     var value = typeof variable === "object" ? variable.value : variable;
>     if (variable.type !== undefined) {
>         type = variable.type;
>     }
>     else {
>         switch (typeof value) {
>             case "object":
>                 type = "Object";
>                 break;
>             case "boolean":
>                 type = "Boolean";
>                 break;
>             case "number":
>                 type = value % 1 === 0 ? "Int" : "Float";
>                 break;
56,57d124
<         defaultAdapter = new DefaultSubscriptionAdapter_1.default(options);
<         return defaultAdapter.subscriptionsBuilder(options);
59,62c126,127
<     if (adapter) {
<         // @ts-ignore
<         customAdapter = new adapter(options);
<         return customAdapter.subscriptionBuilder();
---
>     if (typeof variable === "object" && variable.required) {
>         type += "!";
64,65c129
<     defaultAdapter = new DefaultSubscriptionAdapter_1.default(options);
<     return defaultAdapter.subscriptionBuilder();
---
>     return type;
67d130
< exports.subscription = subscriptionOperation;

Is the type of variables correct in NestedField?

variables: IQueryBuilderOptions[];

Please refer to the above line, the type of variables in NestedField was set to IQueryBuilderOptions[], just wondering if that's correct at all?

If we look at it here:

test("generates query with variables nested in fields", () => {

The variables object inside nested field would certainly fail the type check IQueryBuilderOptions[].

Single query, multiple operations

I have a case roughly like this:

query SpeakerTweetTemplateQuery($conferenceId: ID!, $contactName: String!) {
  contact(contactName: $contactName, conferenceId: $conferenceId) {
    name
  }
  conference(id: $conferenceId) {
    name
  }
}

The point is that I would like to execute multiple operations within a single query. As far as I can see, the current API isn't flexible enough for this purpose.

I can work around this by performing multiple separate requests. Any better ideas? Should I try to PR a generalization like this?

v3.1.2 breaks build

Since v3.1.2 importing breaks typescript builds (not sure if the same happens with js)

Add enum

i have some query that need add Enum like that:

{
  diagnostic__defects(page: 1, orderBy: [{field: IS_FUNCTIONAL_DEFECT, order: DESC}]) {
    data {
      id
      name
    }
  }
}

IS_FUNCTIONAL_DEFECT and DESC are ENUM, can't be wrapped by quote

TypeError: innerFields.forEach is not a function

Hi!

I get an error when I try to collect a query
TypeError: innerFields.forEach is not a function

For example, the query is as follows
[ { operation: 'someoperation', fields: [ 'id', { operation: 'someoperation2', fields: [ 'name' ] } ] } ]

all but two of the tests are ignored

There is a test.only hiding in src/index.test.ts which is causing jest to only run two out of the 92 tests in the test suite. Running them results in 13 tests failing, all for white space issues. I suggest making a new jest matcher which removes any whitespace that's ignored by graphql anyway.

Implement ES6 export module

Hello.
Angular 10 show a warning for every dependency that is imported in ES5. From now, angular require ES6 module to optimize build process.

More info here:
https://angular.io/guide/build#configuring-commonjs-dependencies

Gql-query-builder show warning like this:
my-service.ts depends on 'gql-query-builder'. CommonJS or AMD dependencies can cause optimization bailouts.

Can this cool stuff for sure have ES6 export module as well within current commonJS?

Thanks and have a great day:)

Question: nested variables as object

Hi, thank you all for the wonderful library,

I have to create a quey as follow:

   "query":"mutation($params:StoreCreateRequest!){
      createStore(params: $params){
       name
      }
   }",
   "variables":{
       "params":{
           "organization_id":"abc-def",
           "name":"my-store",
           "type":"Kafka",
           "uris":["http://ds.io"],
           "availability_zone":"a",
           "secret":{"value":[ { key: "a", value: "b" }] },
           "metadata":{"value":[ { key: "c", value: "d" } ]}
       }
    }


Is it possible to generate it with gql-query-builder?

Many thanks in advance!

incorrect checks for an object-like value

throughout the code there are checks like;

const value = typeof variable === "object" ? variable.value : variable;

however, typeof will also result in "object" if value is null
in which case the above code will simply fail

I'm considering making a PR in a few days to address this issue

support for primitive return types?

it seems the builder expects an object to always be returned in a graphql response since the fields arg is required. But what if the graphql server responds with a primitive? (eg. GraphQLBoolean)

Example:

// mutation portion of schema
new GraphQLObjectType({
  name: 'RootMutation',
  fields: { 
    logout: {
      type: GraphQLBoolean,
      resolve: async () => await pretendToLogUserOut(), // returns boolean
    }
  }
});
// query
import { mutation } from 'gql-query-builder';

const logoutMutation = mutation({ operation: 'logout', fields: [] });
console.log(logoutMutation.query);
// query output
mutation {
  logout {
    // this causes a 400 since i dont list any fields but that's because the response doesnt return `fields`, it just returns a bool
  }
}

// desired query output
mutation {
  logout
}

The result is a 400 since this is a malformed query string so it seems the query builder does not have support for handling primitive return values?

Use for gatsby.js

Can i using this lib to create graphql for gatsby

const { graphql } = require('gatsby')

If can, can you give me example to use this lib for useStaticQuery of graphql with gatsby ?

below codes is gatsby method

import { graphql, useStaticQuery } from "gatsby"
const imagesData = useStaticQuery(graphql`
  query {
    images: allFile(filter: { sourceInstanceName: { eq: "images" } }) {
      edges {
        node {
          relativePath
          absolutePath
          name
          childImageSharp {
            gatsbyImageData
          }
        }
      }
    }
  }
  `)

Custom variable parameter

Hey,
I found this library and is really nice and easy to use, however I found a case where I would need a help

I need to write query like

query ($owner: String!) {
  nftEntities(where: {currentOwner_eq: $owner}) {
    id
    metadata
  }
}

and so far my hack is

query({
  operation: 'nfts: nfts: nftEntities(where: {currentOwner_eq: "vikiival"})',
  fields: ['id', 'metadata']
})

The thing I need is to somehow wrap the variable into the object.
Question is: Is it possible to do that? Or should I just pass the whole object ({currentOwner_eq: "vikiival"}) as the variable ?

Merging Queries

Hi its not really an issue more of question and if the answer is no then a feature request

query gamesAndLeagues {
  games(query: {result: "void"}) {
    teamOne {
      id
    }
    teamTwo {
      id
    }
    result
  }
  leagues(query: {vip: false}) {
    _id
  }
}

this is a query i hit to get data from mongodb realms via gql.

I was wondering if it is possible to build this query that calls 2 collections via a single call?

Im thinking its not possible based on the docs

Thanks

Can't pass in variables.

Hello. Help me, please.

gql.query({
        operation: 'user',
        variables: { id: 333 },
        fields: ['name', 'balance'],
}).query;

returns

query ($id: Int) { user (id: $id) { name, balance } }

instead of

query ($id: Int) { user (id: 333) { name, balance } }

Shortly, your feature doesn't inject variables values into resulting query string.

operationName not included as a root key of the query object

We've been using gql-query-builder to replace hand-written queries in our service layer and so far it's working really well, thanks for creating this library.

I noticed recently that the GraphQL spec includes the following recommendation:

A standard GraphQL POST request should use the application/json content type, and include a JSON-encoded body of the following form:

{
  "query": "...",
  "operationName": "...",
  "variables": { "myVariable": "someValue", ... }
}

We've started work to stub out different gql queries and responses in our cypress test suite, and one of the recommendations is to use an explicit operationName in your queries, and then use this part of the request object to determine which response to send:

// Utility to match GraphQL mutation based on the operation name
export const hasOperationName = (req, operationName) => {
  const { body } = req
  return (
    body.hasOwnProperty('operationName') && body.operationName === operationName
  )
}

cypress.intercept('POST', '/graphql', req => {
  if (hasOperationName(req, 'getSite') {
    req.alias = 'getSite';
    req.send({ fixture: 'getSiteFixturre' });
  }
});

This code looks for the operationName in the root of the request body, and it seems this approach works well for a lot of developers, but isn't working for us because gql-query-builder only includes the operationName in the query itself.

For now we're working around this simply like:

  const gqlQuery = query({
    operation: 'site',
    variables: ...,
    fields: ...,
  }, null, { operationName: 'getSite' }));
  // manually add operationName
  gqlQuery.operationName = 'getSite';

However, if gql-query-builder did this for us we could use the intended syntax:

  const gqlQuery = query({
    operation: 'site',
    variables: ...,
    fields: ...,
  }, null, { operationName: 'getSite' });

Do you think this is something the library should support in the default adapter, and if so would you like me to make a pull request?

Default mutation adapter ignores variable `name`

When generating a mutation and passing in an array of options, the name field is ignored for variables:

Mutation generation:

import { mutation } from 'gql-query-builder';

mutation(itemIds.map((_, index) => ({
    operation: `delete_${index}: deleteThing`,
    fields: [
        {
            userErrors: ['message', 'path'],
        },
    ],
    variables: {
        [`input${index}`]: {
            name: 'input',
            type: `DeleteThingInput`,
            required: true
        }
    }
}))).query;

Expected output:

mutation ($input0: DeleteThingInput!, $input1: DeleteThingInput!, $input2: DeleteThingInput!) {
    delete_0: deleteThing (input: $input0) {
      userErrors { message, path }
    }
    delete_1: deleteThing (input: $input1) {
      userErrors { message, path }
    }
    delete_2: deleteThing (input: $input2) {
      userErrors { message, path }
    }
}

Actual output:

mutation ($input0: DeleteThingInput!, $input1: DeleteThingInput!, $input2: DeleteThingInput!) {
    delete_0: deleteThing (input0: $input0) {
      userErrors { message, path }
    }
    delete_1: deleteThing (input1: $input1) {
      userErrors { message, path }
    }
    delete_2: deleteThing (input2: $input2) {
      userErrors { message, path }
    }
}

When provided, the variable name should be used as input to each mutation, rather than the key. The problematic code appears to be:

private queryDataNameAndArgumentMap() {
return this.variables && Object.keys(this.variables).length
? `(${Object.keys(this.variables).reduce(
(dataString, key, i) =>
`${dataString}${i !== 0 ? ", " : ""}${key}: $${key}`,
""
)})`
: "";
}

The queryDataNameAndArgumentMap in src/Utils.ts could be used to solve the issue, as it already handles name.

custom filter

hi

I make my geoserver using Hasura.
I use your library to generate requests with apollo-client.

I need to get a graphql request like:

query network($geom: Geometry!){
    network(where: {geom: {_st_intersects: $geom}}){
        geom
    }
}

I think that you need to do this custom filter like example

Support array variables

I want to pass an array of strings as a variable to a query (e.g. a list of tags that should be searched), I have no choice except change my type from String to [String]. Also, if none of the array items can be null or undefined, I should change this to [String!].
It doesn't seem good practice, so I suggest using something like Nexus list to specify both array and nullability of array items.
For example a variable input like this:

tags: {
  type: 'String',
  value: tags,
  list: [true],
  required: true,
}

should be generated as: $tags: [String!]!

So the type of Variable should be:

interface Variable {
  type: String;
  value: any;
  list?: true | [boolean];
  required: boolean;
}

list: true means the variable should be in array format but its items are nullable (that equals to list: [false]
list: [true] means the variable should be in array format and its items are not nullable
and list: undefined means the variable is not in array format

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.