gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.29k stars 10.31k forks source link

[feature] Add support for arguments on GraphQL fields that return arrays #3643

Closed geoffdavis92 closed 5 years ago

geoffdavis92 commented 6 years ago

Description

It would be nice to have the ability to assign arguments onto dynamically-created schemas' node fields that return arrays.

Arguments could be near-identicle to *Connection types:

Those existing arguments could be modified to support array-specific needs, like exposure of an __index-type field and array index wrapping:

characters(sort: { fields: [__index], order: ASC }, limit: 2)

New arguments could also be created to simplify filtering arrays and/or return specific indicies:

@KyleAMathews suggested I open an issue to add this support for passing arguments to sub-arrays on the Discord chat; the only issues that I found that pertained to this issue are #2430 and #1645.

Environment

Gatsby version: ^1.9.158 Node.js version: 8.9.1 Operating System: MacOS El Capitan 10.11.6

Steps to reproduce

I have set up a working demo project that features some sample data, some working queries, and an example of the aforementioned experimental array field arguments.

flmuel commented 6 years ago

maybe related to #3190

KyleAMathews commented 6 years ago

@flmuel no these are unrelated — @geoffdavis92 is asking for the ability to sort/filter on graphql lists not linked nodes.

loremipson commented 6 years ago

I think I'm running into this issue right now with gatsby-transformer-json. Any array data in my json is being transformed into an InputObject and available in Graph via in: []? Anytime I include this in in my query/filter I am getting null data returned.

In my json, I have an array of objects, I would expect my query to be this, or similar:

{
    dataJson(data: { pages: { name: { eq: "index" } }) {
        data {
          pages {
            name
          }
       }
    }
}

Because of that in, graph "suggests" this query:

{
    dataJson(data: { pages: { in: { name: { eq: "index" } } }) {
        data {
          pages {
            name
          }
       }
    }
}

But anytime in is included at all, data just returns null.. I'm guessing this is related to this issue, but I'm curious if I'm just writing my query wrong.

m-allanson commented 6 years ago

@pieh might have an answer for @loremipson's question above?

pieh commented 6 years ago

It seems gatsby doesn't actually support properly constructing input schema for array of objects (I don't think we should have that eq inside in operator). Will check if we can fix it.

LekoArts commented 6 years ago

@pieh I'd need that feature for my Prismic source to grab the tags.

I get as an output:

"tags": [
                {
                  "tag": {
                    "document": [
                      {
                        "data": {
                          "tag": "elitepvpers"
                        }
                      }
                    ]
                  }
                },
                {
                  "tag": {
                    "document": [
                      {
                        "data": {
                          "tag": "Wallpaper"
                        }
                      }
                    ]
                  }
                }
              ],
KyleAMathews commented 6 years ago

@LeKoArts a good start to fixing this would be to create a PR with a new test for this functionality in https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/schema/__tests__/infer-graphql-input-type-test.js

That test should be failing and then it'd be easy for one of us to figure out how to fix it.

bzhr commented 6 years ago

@KyleAMathews @LeKoArts I think that the error happens when filtering on an array of objects. I think this kind of data structure is needed in order to re-create the error.

LekoArts commented 5 years ago

Feature got merged in the meantime.

geoffdavis92 commented 5 years ago

Thanks all! Great to see @KyleAMathews @LekoArts

senorgeno commented 5 years ago

Hey @LekoArts or @KyleAMathews I can't work out from the docs or code how this is meant to work if it has been merged. I get into a circular loop of duplicate issues.

I have this query

{
  dataJson(data: {allRestaurants: {elemMatch: {id: {eq: "132"}}}}) {
    data {
      allRestaurants {
        id
        title
      }
    }
  }
}

but it doesn't do any filtering. e.g. results

{
  "data": {
    "dataJson": {
      "data": {
        "allRestaurants": [
          {
            "id": "132",
            "title": "Jervois Steak House"
          },
          {
            "id": "682",
            "title": "Bessie"
          },
          {
            "id": "71",
            "title": "Blue Kanu"
          },
          {
            "id": "1050",
            "title": "Bazaar Interactive Marketplace"
          },
          {
            "id": "1300",
            "title": "Louis Champagne & Oyster Bar"
          },
          {
            "id": "2018",
            "title": "Takumi Japanese Restaurant & Bar"
          },
          {
            "id": "1343",
            "title": "Euro Bar & Restaurant"
          },
          {
            "id": "2360",
            "title": "Orleans Auckland"
          },
          {
            "id": "1053",
            "title": "The Grille by Eichardt's"
          },
          {
            "id": "2350",
            "title": "Orleans"
          },
          {
            "id": "2245",
            "title": "Vault 21"
          },.......

Any idea what I am doing wrong or is this not possible? My GraphQL data is being generated from gatsby-transformer-json

senorgeno commented 5 years ago

Never mind, i ended up building a source plugin for my use case

AleC77 commented 5 years ago

Never mind, i ended up building a source plugin for my use case

Can you provide a link for the source plugin? I have the same problem. Thank you

senorgeno commented 5 years ago

@AleC77 it is currently part of my private repository. It works for my use case but i think it would need more work for it be useful to others.

AleC77 commented 5 years ago

Can you send me a short piece of code of that? I am becoming crazy to find a solution. It looks it is impossible with graphql filter the content of json file for me

senorgeno commented 5 years ago

@AleC77 have a look at what this module does with create node - https://github.com/GraphCMS/gatsby-source-graphcms/blob/master/src/util.js and then look at this tutorial - https://www.gatsbyjs.org/docs/source-plugin-tutorial/

You basically need to take the JSON, loop over it and create a gatsby node.

forEach(data, (value, key) => {
        const type = extractTypeName(key);
        forEach(value, (obj) => {
          const { id } = obj;

          const jsonNode = JSON.stringify(obj);
          const gatsbyNode = {
            id,
            ...obj,
            parent: null,
            children: [],
            internal: {
              type: type,
              content: jsonNode,
              contentDigest: createContentDigest(obj)
            }
          };

          createNode(gatsbyNode)
        });
      });
AleC77 commented 5 years ago

Thank you so much for the help @senorgeno