Can I make my graphql query multipurpose? - graphql

I would like to query products by different filters and criteria so I have written multiple queries for my frontend for each case (shown below). Is there a way I can write and use one "multipurpose" query instead of these?
const GET_PRODUCTS = gql`
query {
products {
...productFragment
}
}
${PRODUCT_FRAGMENT}
`
const GET_PRODUCTS_BY_PRICE = gql`
query($sortFilter: String) {
products(sort: $sortFilter) {
# (sort: "price:asc") or (sort: "price:desc")
...productFragment
}
}
${PRODUCT_FRAGMENT}
`
const GET_PRODUCTS_BY_CATEGORY = gql`
query($categoryId: String) {
products(where: { categories: { id: $categoryId } }) {
...productFragment
}
}
${PRODUCT_FRAGMENT}
`
const GET_PRODUCTS_BY_CATEGORY_AND_PRICE = gql`
query($sortFilter: String, $categoryId: String) {
products(sort: $sortFilter, where: { categories: { id: $categoryId } }) {
...productFragment
}
}
${PRODUCT_FRAGMENT}
`
Looks like I can write a helper fn like this then:
function getRequiredProductsQuery({ sortFilter, categoryId }) {
if (sortFilter && categoryId) {
return { key: 'PRODUCTS_BY_CATEGORY_AND_PRICE', query: GET_PRODUCTS_BY_CATEGORY_AND_PRICE }
}
if (sortFilter) {
return { key: 'PRODUCTS_BY_PRICE', query: GET_PRODUCTS_BY_PRICE }
}
if (categoryId) {
return { key: 'PRODUCTS_BY_CATEGORY', query: GET_PRODUCTS_BY_CATEGORY }
}
return { key: 'PRODUCTS', query: GET_PRODUCTS }
}
Is it really all necessary?

ok, I figured that I can provide default params like $categoryId: String = "id:asc"

Related

How to implement a filter on a query in Apollo?

I'm attempting to filter a query by a specific field. I can achieve this in Apollo explorer in dev tools but I can't seem to translate this into code.
The following works in Apollo explorer:
query ListUsersByType($filter: TableUsersFilterInput) {
listUsers(filter: $filter) {
items {
email
id
type
}
}
}
{
"filter": {
"type": {
"eq": "ADMIN"
}
}
}
I am unsure how this translates to the code using the useQuery hook however.
When I try the following it doesn't filter the list at all, it just fetches all of them regardless of type:
const ListUsersByType = gql`
query ListUsersByType($type: TableUsersFilterInput) {
listUsers(filter: $type) {
items {
email
id
type
}
}
}
`
const { data, loading, error } = useQuery(ListUsersByType, {
variables: {
filter: {
type: {
eq: 'ADMIN',
},
},
},
})
What am I missing here?
Your names are not correct
Here you say filter will use the variable type
const ListUsersByType = gql`
query ListUsersByType($type: TableUsersFilterInput) {
listUsers(filter: $type) {
items {
email
id
type
}
}
}
`
And here you pass filter
const { data, loading, error } = useQuery(ListUsersByType, {
variables: {
filter: {
type: {
eq: 'ADMIN',
},
},
},
})
You can
First solution
replace $type by $filter
const ListUsersByType = gql`
query ListUsersByType($filter: TableUsersFilterInput) {
listUsers(filter: $filter) {
items {
email
id
type
}
}
}
`
Second solution
rename the variable filter to type
const { data, loading, error } = useQuery(ListUsersByType, {
variables: {
type: {
type: {
eq: 'ADMIN',
},
},
},
})
My opinion
I let you choose but the first option seems the best

How to make pagination on alternative arguments (Apollo)

I have two arguments (skip and take) and they are different from standart "offset" and "limit".
How do I make this scheme work:
function App() {
const { networkStatus, error, data, fetchMore } = useQuery(ALL_LINKS, { variables: { take: 30, skip: 0 } });
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
feed: offsetLimitPagination()
}
}
}
});
export const ALL_LINKS = gql`
query AllLinks ($skip: Int, $take: Int) {
feed ( skip: $skip, take: $take ) {
links {
id
}
}
}`;
Custom name for arguments inside offsetLimitPagination(["skip", "take"]) doesn`t work.
An empty array is returned to me.
Thanks for answer!

WpGraphQL query returns null

I'm having this GraphQL query from headless Wordpress in Nexjs via WpGraphQl plugin:
export const GET_POSTS_BY_CATEGORY_SLUG = gql`
query GET_POSTS_BY_CATEGORY_SLUG( $slug: String, $uri: String, $perPage: Int, $offset: Int ) {
${HeaderFooter}
page: pageBy(uri: $uri) {
id
title
content
slug
uri
seo {
...SeoFragment
}
}
categories(where: {slug: $slug}) {
edges {
node {
slug
posts: posts(where: { offsetPagination: { size: $perPage, offset: $offset }}) {
edges {
node {
id
title
excerpt
slug
featuredImage {
node {
...ImageFragment
}
}
}
}
pageInfo {
offsetPagination {
total
}
}
}
}
}
}
}
${MenuFragment}
${ImageFragment}
${SeoFragment}
`;
And this is my getStaticProps function:
export async function getStaticProps(context) {
const { data: category_IDD } = await client.query({
query: GET_POSTS_BY_CATEGORY_SLUG,
});
const defaultProps = {
props: {
cat_test: JSON.parse(JSON.stringify([category_IDD])),
},
revalidate: 1,
};
return handleRedirectsAndReturnData(defaultProps, data, errors, "posts");
}
If i pass it like this in props:
const defaultProps = {
props: {
cat_test: category_IDD,
},
i get an error saying:
SerializableError: Error serializing `.cat_test` returned from `getStaticProps` in "/category/[slug]". Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit this value.
But when i JSON.parse as the code above, i get null
Whats wrong with this query?
Just noticed that the $slug is an array of strings, so here should be:
query GET_POSTS_BY_CATEGORY_SLUG( $slug: [String], $uri: String, $perPage: Int, $offset: Int )
instead of $slug: String
You're not actually passing the $slug variable to the query.
For instance if your page route is /category/[slug].js your getStaticProps should look something like this.
export async function getStaticProps(context) {
const { slug } = context.params;
const { data: category_IDD } = await client.query({
query: GET_POSTS_BY_CATEGORY_SLUG,
variables: { slug },
});
const defaultProps = {
props: {
cat_test: JSON.parse(JSON.stringify([category_IDD])),
},
revalidate: 1,
};
return handleRedirectsAndReturnData(defaultProps, data, errors, "posts");
}

Graphql with Apollo - refactor queries, return objects are repeating (same fields in diff queries)

I have several queries that have same return types:
// Query 1
gql`
mutation insert_shops_users($shopId: uuid) {
insert_shops_users(objects: [{ shopId: $shopId }]) {
affected_rows
returning {
Shop {
id
users {
userId
}
}
}
}
}
`,
// Query 2
gql`
mutation delete_shops_users_by_pk($shopId: uuid!, $userId: String!) {
delete_shops_users_by_pk(shopId: $shopId, userId: $userId) {
Shop {
id
users {
userId
}
}
}
}
`,
Now, I'd like to extract this part eg under name ShopUserResult and use that in both queries:
Extracted under ShopUserResult
Shop {
id
users {
userId
}
}
Resulting queries
// Query 1 - after refactor
gql`
mutation insert_shops_users($shopId: uuid) {
insert_shops_users(objects: [{ shopId: $shopId }]) {
affected_rows
returning {
ShopUserResult
}
}
}
`,
// Query 2 - after refactor
gql`
mutation delete_shops_users_by_pk($shopId: uuid!, $userId: String!) {
delete_shops_users_by_pk(shopId: $shopId, userId: $userId) {
ShopUserResult
}
}
`,
I'm quite new at graphql, any advice on refactoring would be much appreciated, thank you.
It's possible to refactor repeating sets of fields using fragments (source 1, source 2):
Query - before
gql`
mutation insert_shops_users($shopId: uuid) {
insert_shops_users(objects: [{ shopId: $shopId }]) {
affected_rows
returning {
Shop {
id
users {
userId
}
}
}
}
}
`,
Query - after using fragments
Fragment
const ShopWithUsers = gql`
fragment ShopWithUsers on shops {
id
users {
userId
}
}
`
Query
gql: gql`
mutation insert_shops_users($shopId: uuid) {
insert_shops_users(objects: [{ shopId: $shopId }]) {
affected_rows
returning {
Shop {
...ShopWithUsers
}
}
}
}
${ShopWithUsers}
`,

how to pass a variable to graphql query?

I have a question.
There is a function that returns the result of a graphql query. In this function, I want to pass the arguments that will be used in the request, for example, to control order direction.
How can i do this?
1) Fucntion query
import { useStaticQuery, graphql } from "gatsby";
export const useSiteMetadata = (dir) => {
const {allContentfulBlogPost:{edges}} = useStaticQuery(
graphql`
query {
allContentfulBlogPost(
sort:{
fields: published,
order: $dir
}
){
edges{
node{
name,
alias,
published,
id
}
}
}
}
`
);
return edges;
};
2)Function call
const res = useSiteMetadata('ASC');
exempel code
import { useStaticQuery, graphql } from "gatsby";
export const useSiteMetadata = (dir) => {
const { allPostsAsc, allPostsDsc } = useStaticQuery(
graphql`
query {
allPostsAsc: allContentfulBlogPost(sort: { fields: published, order: "ASC" }) {
edges {
node {
name
alias
published
id
}
}
}
allPostsDsc: allContentfulBlogPost(sort: { fields: published, order: "DSC" }) {
edges {
node {
name
alias
published
id
}
}
}
}
`
);
const posts = {
ASC: allPostsAsc,
DSC: allPostsDsc
}
return posts[dir]
};

Resources