Repository: edgedb/edgedb

Issue:
GraphQL: filter with IN 
It would be very handy to be able to filter for multiple IDs from the GraphQL API.

Example:
```
query {
  Person(filter: {id: {in: ["foo", "bar"]} }) {
    name
  }
}
```

Expected return:
```
{
  "data": {
     "Person": [
        {
           "id": "foo",
           "name": "alice"
        },
        {
           "id": "bar",
           "name": "bob"
        }
     ]
  }
}
```


Discussion:
Great idea. I changed the title to reflect a broader proposal to support the `in` operator in filters.

Resolving patch:
diff --git a/edb/graphql/translator.py b/edb/graphql/translator.py
--- a/edb/graphql/translator.py
+++ b/edb/graphql/translator.py
@@ -1383,6 +1383,14 @@ def visit_ObjectFieldNode(self, node):
                 # The binary operator that we need here is "="
                 op = '='
 
+            elif op == 'IN':
+                # Instead of wrapping the values in an array, wrap
+                # them in a set
+                value = qlast.FunctionCall(
+                    func='array_unpack',
+                    args=[value],
+                )
+
             elif self._context.right_cast is not None:
                 # We don't need to cast the RHS for the EXISTS, only
                 # for other operations.
diff --git a/edb/graphql/types.py b/edb/graphql/types.py
--- a/edb/graphql/types.py
+++ b/edb/graphql/types.py
@@ -273,6 +273,7 @@ def parse_decimal_literal(
 
 GQL_TO_OPS_MAP = {
     'exists': 'EXISTS',
+    'in': 'IN',
     'eq': '=',
     'neq': '!=',
     'gt': '>',
@@ -1136,6 +1137,8 @@ def _make_generic_filter_type(
 
         # Always include the 'exists' operation
         fields['exists'] = GraphQLInputField(GraphQLBoolean)
+        # Always include the 'in' operation
+        fields['in'] = GraphQLInputField(GraphQLList(GraphQLNonNull(base)))
         for op in ops:
             fields[op] = GraphQLInputField(base)
 


Test patch:
diff --git a/tests/test_http_graphql_query.py b/tests/test_http_graphql_query.py
--- a/tests/test_http_graphql_query.py
+++ b/tests/test_http_graphql_query.py
@@ -3916,6 +3916,45 @@ def test_graphql_functional_exists_06(self):
             ]
         })
 
+    def test_graphql_functional_in_01(self):
+        self.assert_graphql_query_result(r"""
+            query {
+                User(
+                    filter: {name: {in: ["Alice", "Bob"]}},
+                    order: {name: {dir: ASC}}
+                ) {
+                    name
+                }
+            }
+        """, {
+            "User": [
+                {
+                    "name": "Alice",
+                },
+                {
+                    "name": "Bob",
+                },
+            ]
+        })
+
+    def test_graphql_functional_in_02(self):
+        self.assert_graphql_query_result(r"""
+            query {
+                User(
+                    filter: {name: {in: ["Zoe", "Alice"]}},
+                    order: {name: {dir: ASC}}
+                ) {
+                    name
+                }
+            }
+        """, {
+            "User": [
+                {
+                    "name": "Alice",
+                },
+            ]
+        })
+
 
 class TestGraphQLInit(tb.GraphQLTestCase):
     """Test GraphQL initialization on an empty database."""