Use variables in Shopify Bulk Operations graphql mutation - graphql

I am trying to use graphql to query a store's orders in a bulk operation. I am using a tags variable in the graphql request to query orders with specific tags. I have been following Shopify's documentation in order to do this.
Here is what I've been trying:
const variables = {
"tags": "tag:foo AND tag:bar"
};
const query = gql`
mutation getOrders($tags: String!) {
bulkOperationRunQuery(
query:"""
query {
orders(query: $tags) {
edges {
node {
id
email
}
}
}
}
"""
) {
bulkOperation {
id
url
status
}
userErrors {
field
message
}
}
}
`;
const bulkOperation = await graphQLClient.request(query, variables);
However, I always get this error back from the api:
Variable $tags is declared by getOrders but not used
Does anyone know if there is a way to use a graphql variable in that bulk operation? Thanks!

""" is multiline string based on docs, which would means its just a string and no vars are allowed. You can use js variable substitution like ${tags} inside templated string and bypass this all together or try if concatenation works like """ 1st part """" + $tags + """ 2nd part """

Related

Creating dynamic graphql query using apollo/client

I am trying to create a graphql query where the query data type and filter parameters will be passed dynamically based on user input.
I have written the below query which filters using only one field shipdate.
const GET_SHIPDATA_WITH_FILTER = gql`
query GetShipData($shipdateStart: timestamptz, $shipdateEnd: timestamptz, $limit: Int) {
shipdata(where: {shipdate: { _gte: $shipdateStart, _lte: $shipdateEnd}},limit: $limit) {
status
import_time
shipdate
}
}
`;
const variables = {
shipdateStart: "some date",
shipdateEnd: "some date",
limit: 50,
};
If no filter is passed I'm using this one
const GET_SHIPDATA = gql`
query GetShipData($limit: Int) {
shipdata(limit: $limit) {
status
import_time
shipdate
}
}
`;
const variables = {
limit: 50,
};
You can see I have written two queries to handle two types of filters which won't work if I want to add more filters.
Now I am trying to write a single dynamic query where if the user wants to add more filters like status: {_eq: $status} or import_time: { _gt: $importTimeStart, _lt: $importTimeEnd} then I will pass the variables and the query will dynamically handle the filters. Something like
const GET_SHIPDATA = gql`
query GetShipData($allfilters: AllFilterTypes) {
shipdata(filter: $allfilters) {
status
import_time
shipdate
}
}
`;
const variables = {
//pass allFilters based on user input,
};
Btw I'm using react and hasura if it helps anyway.
Hasura already exposes types in your GraphQL schema that refer to "filter conditions". In Hasura, they're called Bool_Exp (short for boolean expression) and they map directly to the where clause.
If you just update your query to receive a shipdata_bool_exp you'll be able to build up a dynamic filter expression in your application code and it will work as expected.
const GET_SHIPDATA_WITH_FILTER = gql`
query GetShipData($filter: shipdata_bool_exp!) {
shipdata(where: $filter,limit: $limit) {
status
import_time
shipdate
}
}
`;

Dynamically choose query variables in React Apollo

I'd like to be able to dynamically choose which query variables I use in GraphQL.
For example, it seems a little redundant to need three separate queries:
const getAllStops = gql`
query trafficStops {
trafficStops {
id
date
}
}
`
const getStopsAfter = gql`
query trafficStops($after: String!) {
trafficStops(after: $after) {
id
date
}
}
`
const getStopsBefore = gql`
query trafficStops($before: String!) {
trafficStops(before: $before) {
id
date
}
}
`
Is there a way in which I could pass not just the variables before or after but whether I'd like to use one, the other, neither, or both into a single query instead of having multiple queries?
Yes, you just have to make your arguments optional. The exclamation mark at String! requires the argument to be a string and not null. Hence, by removing it you could write your single query as
const getAllStops = gql`
query trafficStops($after: String, $before: String) {
trafficStops(after: $after, before: $before) {
id
date
}
}
`

How to generate the same graphql query with different fields

I'm using graphql-tag so i'm going to use that syntax.
Lets say I have this query:
const query = gql`
query user(id: String) {
user(id: $id) {
id
}
}
`
Whats the best patten to reuse that same query document node if on a different call I want the fields username and email in addition to id without having to rewrite the entire query again like:
const query = gql`
query user(id: String) {
user(id: $id) {
id
username
email
}
}
`
I'm using react-apollo on the frontend if that makes things anymore interesting.
Edit:
Just to clarify... something like this
const userIdFrag = gql`
fragment UserId on User {
id
}
`
const fullUserFrag = gql`
fragment FullUser on User {
id
username
email
}
`
const generateQuery = (documentNode) => {
return gql`
query user(id: String) {
user(id: $id) {
...documentNode
}
}
${documentNode}
`
}
const idQuery = generateQuery(userIdFrag);
const fullUserQuery = generateQuery(fullUserFrag);
(The above does work but give me errors from graphql in the console, which leads me to believe this is not something I should be doing)
Based on your comment the following should work:
const generateQuery = (documentNode, fragment) => {
return gql`
query user(id: String) {
user(id: $id) {
...${fragment}
}
}
${documentNode}
`
}
const idQuery = generateQuery(userIdFrag, 'UserId');
const fullUserQuery = generateQuery(fullUserFrag, 'FullUser');
Basically the fragment name used is the actual one that needs to be spread while the whole documentNode object is put at the end, after query's closing bracket
I am not the very expert on the topic, but here is what I have been able to find out. (if you see any mistakes in my assumptions, let me know).
I found this article that makes some good points against dynamically generating gql queries/mutations. It seems like you get some nice benefits with the static approach, although it's a bit more typing.
But, in case you do need to have dynamic fields, I haven't been able to find anything bad about using the #skip directive GraphQL provides. Here the docs ref.
For the case of using it in react-apollo they also have it in their docs.
So, your code can end up looking something like this:
const query = gql`
query user($id: String, $skipUserMeta: Boolean!) {
user(id: $id) {
id
username #skip(if: $skipUserMeta)
email #skip(if: $skipUserMeta)
}
}
`
You just pass the skipUserMeta as a variable alongside the id field.
NOTE: I actually found a video which talks about the exact same approach here

How to conditionally apply a GraphQL filter based on the value of a passed in argument?

Update: for my particular use case, #langpavel's solution will work. However, it avoids answering the original question... is it possible to conditionally apply a GraphQL filter based on the value of a passed in argument?
I am passing in an argument into my GraphQL query called $env that I would like to use in conjunction with a draft boolean in the markdown frontmatter of my blog posts in order to filter out drafts during production.
My query, in an abbreviated form, is below. As you can see, I have a filter function that is filtering based on whether the blog post is a draft or not. What I can't figure out how to do is take advantage of the $env argument to only apply the filter when $env is equal to production.
export const pageQuery = graphql`
query BlogPosts($env: String!) {
markdownRemark(
filter: { frontmatter: { draft: { eq: true } } }
) {
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
draft
}
}
}
`
In case of gatsby, you should probably write two queries and select one conditionally based on process.env.NODE_ENV:
export const pageQuery = (process.env.NODE_ENV === 'production') ?
graphql`
query BlogPosts {
markdownRemark(
filter: { frontmatter: { draft: { ne: true } } }
) { frontmatter { ... } }
}
` : graphql`
query BlogPosts {
markdownRemark { frontmatter { ... } }
}
`
The GraphQL query you provided is invalid because the $env variable is not used in any fields. I think for your purpose, $env would be better passed outside of the GraphQL query. If you're serving GraphQL over HTTP, you could send it as a query parameter or an HTTP header. Then you could pass the value to your GraphQL resolvers using the context concept that most GraphQL libraries provide.

GraphQL Query with variables from data object

I have a graphQl query where I use a Prismic uid to get a specific user. Now I also want to get a user space from another prismic set of data called prismicSpaces but instead of looking for the data based on the uid on prismicSpaces I want to pass it an identifier from prismicUsers data object called location_id. Seen as location_id is not at the root like uid how can I use that to pass it down to prismicSpaces ?
below is my current query which works great but I need a way to pass on the location_id like the second example below this.
ps. I'm using gatsby and prismic
export const query = graphql`
query UsersQuery($uid: String!) {
page: prismicUsers(uid: { eq: $uid }) {
uid
type
data {
location_id
}
}
}
spaces: prismicSpaces {
uid
data {
name
}
}
}
`;
Example but this does not work.
export const query = graphql`
query UsersQuery($uid: String!, $space_id:String! ) {
page: prismicUsers(uid: { eq: $uid }) {
uid
type
data {
space_id
}
}
}
spaces: prismicSpaces(uid: {eq: { $space_id }) {
uid
data {
name
}
}
}
`;

Resources