simonw / datasette-graphql

Datasette plugin providing an automatic GraphQL API for your SQLite databases
https://datasette-graphql-demo.datasette.io/
Apache License 2.0
100 stars 6 forks source link

in: and notin: filters work with lists of strings but not with lists of integers #68

Closed simonw closed 3 years ago

simonw commented 3 years ago

This query works: https://datasette-graphql-demo.datasette.io/graphql/fixtures?query=%7B%0A%20%20table_with_pk(filter%3A%20%7Bname%3A%20%7Bin%3A%20%5B%22Row%201%22%2C%20%22Row%202%22%5D%7D%7D)%20%7B%0A%20%20%20%20nodes%20%7B%0A%20%20%20%20%20%20pk%0A%20%20%20%20%20%20name%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A

{
  table_with_pk(filter: {name: {in: ["Row 1", "Row 2"]}}) {
    nodes {
      pk
      name
    }
  }
}

But this query fails with an error: https://datasette-graphql-demo.datasette.io/graphql/fixtures?query=%7B%0A%20%20table_with_pk(filter%3A%20%7Bpk%3A%20%7Bin%3A%20%5B1%2C%202%5D%7D%7D)%20%7B%0A%20%20%20%20nodes%20%7B%0A%20%20%20%20%20%20pk%0A%20%20%20%20%20%20name%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A

{
  table_with_pk(filter: {pk: {in: [1, 2]}}) {
    nodes {
      pk
      name
    }
  }
}

Error:

{
  "data": {
    "table_with_pk": null
  },
  "errors": [
    {
      "message": "sequence item 0: expected str instance, int found",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "table_with_pk"
      ]
    }
  ]
}

I tried using strings instead of integers - table_with_pk(filter: {pk: {in: ["1", "2"]}}) - and got this error:

{
  "data": null,
  "errors": [
    {
      "message": "Argument \"filter\" has invalid value {pk: {in: [\"1\", \"2\"]}}.\nIn field \"pk\": In field \"in\": In element #0: Expected type \"Int\", found \"1\".\nIn field \"pk\": In field \"in\": In element #1: Expected type \"Int\", found \"2\".",
      "locations": [
        {
          "line": 2,
          "column": 25
        }
      ]
    }
  ]
}

notin: is also affected.

simonw commented 3 years ago

This is where those operations are defined - because the type is an integer these integer operations are used: https://github.com/simonw/datasette-graphql/blob/7240262a8cb73a5821b7f1050453e07963579d99/datasette_graphql/utils.py#L313-L321

simonw commented 3 years ago

Then the filters are turned into a Datasette querystring here: https://github.com/simonw/datasette-graphql/blob/7240262a8cb73a5821b7f1050453e07963579d99/datasette_graphql/utils.py#L533-L546

simonw commented 3 years ago

The big clue here is sequence item 0: expected str instance, int found. I think I see the problem:

             if isinstance(value, list): 
                 value = ",".join(value) 

You can't call ",".join() on a list of integers without casting them to strings.