Repository: mirumee/ariadne

Issue:
If value from resolver is callable, call it with **kwargs.
[Apollo doc](https://www.apollographql.com/docs/graphql-tools/resolvers) for default resolver says that if `field_name` resolves to function, it will be called with query arguments:

> Calls a function on obj with the relevant field name and passes the query arguments into that function

This can be useful for situations when parent resolver returned an object with getter functions.


Discussion:

Resolving patch:
diff --git a/ariadne/resolvers.py b/ariadne/resolvers.py
--- a/ariadne/resolvers.py
+++ b/ariadne/resolvers.py
@@ -2,19 +2,23 @@
 from graphql.execution.base import ResolveInfo
 
 
-def resolve_parent_field(parent, name: str):
+def resolve_parent_field(parent, name: str, **kwargs: dict):
     if isinstance(parent, dict):
-        return parent.get(name)
-    return getattr(parent, name, None)
+        value = parent.get(name)
+    else:
+        value = getattr(parent, name, None)
+    if callable(value):
+        return value(**kwargs)
+    return value
 
 
-def default_resolver(parent, info: ResolveInfo):
-    return resolve_parent_field(parent, info.field_name)
+def default_resolver(parent, info: ResolveInfo, **kwargs):
+    return resolve_parent_field(parent, info.field_name, **kwargs)
 
 
 def resolve_to(name: str):
-    def resolver(parent, *_):
-        return resolve_parent_field(parent, name)
+    def resolver(parent, *_, **kwargs):
+        return resolve_parent_field(parent, name, **kwargs)
 
     return resolver
 


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,27 @@
+from unittest.mock import Mock
+
+import pytest
+
+
+@pytest.fixture
+def first_name():
+    return "Joe"
+
+
+@pytest.fixture
+def avatar():
+    return "test-url.com"
+
+
+@pytest.fixture
+def blog_posts():
+    return 3
+
+
+@pytest.fixture
+def mock_user(first_name, avatar, blog_posts):
+    return Mock(
+        first_name=Mock(return_value=first_name),
+        avatar=Mock(return_value=avatar),
+        blog_posts=Mock(return_value=blog_posts),
+    )
diff --git a/tests/test_queries.py b/tests/test_queries.py
--- a/tests/test_queries.py
+++ b/tests/test_queries.py
@@ -196,3 +196,46 @@ def test_mapping_resolver_to_object_attribute():
     result = graphql(schema, "{ user { firstName } }")
     assert result.errors is None
     assert result.data == {"user": {"firstName": "Joe"}}
+
+
+def test_default_resolver(mock_user, first_name, avatar, blog_posts):
+    type_defs = """
+        type Query {
+            user: User
+        }
+
+        type User {
+            firstName: String
+            avatar(size: String): String
+            blogPosts(published: Boolean): Int
+        }
+    """
+
+    resolvers = {
+        "Query": {"user": lambda *_: mock_user},
+        "User": {
+            "firstName": resolve_to("first_name"),
+            "blogPosts": resolve_to("blog_posts"),
+        },
+    }
+
+    schema = make_executable_schema(type_defs, resolvers)
+
+    query = """
+     query User($size: String, $published: Boolean) {
+      user {
+        firstName
+        avatar(size: $size)
+        blogPosts(published: $published)
+      }
+    }
+    """
+    variables = {"size": "200x300", "published": True}
+
+    result = graphql(schema, query, variables=variables)
+    assert result.errors is None
+    assert result.data == {
+        "user": {"firstName": first_name, "avatar": avatar, "blogPosts": blog_posts}
+    }
+    mock_user.avatar.assert_called_with(size=variables["size"])
+    mock_user.blog_posts.assert_called_once_with(published=variables["published"])