Skip to content

Commit ffbddd4

Browse files
committed
feat: add support for graphql-core 3.3.x
1 parent 60a5790 commit ffbddd4

File tree

7 files changed

+210
-109
lines changed

7 files changed

+210
-109
lines changed

.github/workflows/tests.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ jobs:
5353
mode:
5454
- std
5555
- geos
56+
gql-core:
57+
- '3.2'
58+
- '3.3'
5659
exclude:
5760
# Django 4.2 only supports python 3.8-3.12
5861
- django-version: 4.2.*
@@ -89,6 +92,13 @@ jobs:
8992
run: uv sync
9093
- name: Install Django ${{ matrix.django-version }}
9194
run: uv pip install "django==${{ matrix.django-version }}"
95+
- name: Install graphql-core ${{ matrix.gql-core }}
96+
run: |
97+
if [ "${{ matrix.gql-core }}" = "3.2" ]; then
98+
uv pip install "graphql-core>=3.2.0,<3.3.0"
99+
else
100+
uv pip install "graphql-core>=3.3.0a11"
101+
fi
92102
- name: Test with pytest
93103
run: uv run --no-sync pytest -n auto --showlocals -vvv --cov-report=xml
94104
- name: Upload coverage to Codecov

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ repos:
1818
- id: check-xml
1919
- id: check-symlinks
2020
- repo: https://github.com/astral-sh/ruff-pre-commit
21-
rev: v0.14.11
21+
rev: v0.14.13
2222
hooks:
2323
- id: ruff-format
2424
- id: ruff

strawberry_django/optimizer.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
GraphQLWrappingType,
3434
get_argument_values,
3535
)
36-
from graphql.execution.collect_fields import collect_sub_fields
3736
from graphql.language.ast import OperationType
3837
from graphql.type.definition import GraphQLResolveInfo, get_named_type
3938
from strawberry import UNSET, relay
@@ -54,6 +53,7 @@
5453
from strawberry_django.resolvers import django_fetch
5554

5655
from .descriptors import ModelProperty
56+
from .utils.gql_compat import get_sub_field_selections
5757
from .utils.inspect import (
5858
PrefetchInspector,
5959
get_model_field,
@@ -645,13 +645,7 @@ def _get_selections(
645645
info: GraphQLResolveInfo,
646646
parent_type: GraphQLObjectType | GraphQLInterfaceType,
647647
) -> dict[str, list[FieldNode]]:
648-
return collect_sub_fields(
649-
info.schema,
650-
info.fragments,
651-
info.variable_values,
652-
cast("GraphQLObjectType", parent_type),
653-
info.field_nodes,
654-
)
648+
return get_sub_field_selections(info, parent_type)
655649

656650

657651
def _generate_selection_resolve_info(
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from strawberry_django.utils.gql_compat import IS_GQL_32, IS_GQL_33
2+
3+
__all__ = ["IS_GQL_32", "IS_GQL_33"]
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""Compatibility layer for graphql-core 3.2.x and 3.3.x."""
2+
3+
from __future__ import annotations
4+
5+
from typing import TYPE_CHECKING, Any, cast
6+
7+
from graphql import (
8+
FieldNode,
9+
GraphQLInterfaceType,
10+
GraphQLObjectType,
11+
)
12+
from graphql.version import VersionInfo, version_info
13+
14+
if TYPE_CHECKING:
15+
from graphql.type.definition import GraphQLResolveInfo
16+
17+
IS_GQL_33 = version_info >= VersionInfo.from_str("3.3.0a0")
18+
IS_GQL_32 = not IS_GQL_33
19+
20+
21+
def get_sub_field_selections(
22+
info: GraphQLResolveInfo,
23+
parent_type: GraphQLObjectType | GraphQLInterfaceType,
24+
) -> dict[str, list[FieldNode]]:
25+
"""Collect sub-fields, handling API differences between 3.2.x and 3.3.x."""
26+
if IS_GQL_32:
27+
return _get_selections_gql32(info, parent_type)
28+
return _get_selections_gql33(info, parent_type)
29+
30+
31+
def _get_selections_gql32(
32+
info: GraphQLResolveInfo,
33+
parent_type: GraphQLObjectType | GraphQLInterfaceType,
34+
) -> dict[str, list[FieldNode]]:
35+
from graphql.execution.collect_fields import (
36+
collect_sub_fields,
37+
)
38+
39+
return collect_sub_fields(
40+
info.schema,
41+
info.fragments,
42+
info.variable_values,
43+
cast("GraphQLObjectType", parent_type),
44+
info.field_nodes,
45+
)
46+
47+
48+
def _get_selections_gql33(
49+
info: GraphQLResolveInfo,
50+
parent_type: GraphQLObjectType | GraphQLInterfaceType,
51+
) -> dict[str, list[FieldNode]]:
52+
from graphql.execution.collect_fields import (
53+
FieldDetails, # type: ignore
54+
collect_subfields, # type: ignore
55+
)
56+
57+
field_group: list[Any] = [
58+
FieldDetails(node=fn, defer_usage=None) for fn in info.field_nodes
59+
]
60+
61+
collected = collect_subfields(
62+
info.schema,
63+
info.fragments,
64+
info.variable_values,
65+
info.operation,
66+
cast("GraphQLObjectType", parent_type),
67+
field_group,
68+
)
69+
70+
return {
71+
key: [fd.node for fd in field_details]
72+
for key, field_details in collected.grouped_field_set.items()
73+
}

tests/conftest.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,26 @@
1010

1111
import strawberry_django
1212
from strawberry_django.optimizer import DjangoOptimizerExtension
13+
from strawberry_django.utils import IS_GQL_32, IS_GQL_33
1314
from tests.utils import GraphQLTestClient
1415

1516
from . import models, types, utils
1617

18+
19+
def skip_if_gql_32(
20+
reason: str = "Test requires graphql-core 3.3+",
21+
) -> pytest.MarkDecorator:
22+
"""Skip test if running with graphql-core 3.2.x."""
23+
return pytest.mark.skipif(IS_GQL_32, reason=reason)
24+
25+
26+
def skip_if_gql_33(
27+
reason: str = "Test requires graphql-core 3.2.x",
28+
) -> pytest.MarkDecorator:
29+
"""Skip test if running with graphql-core 3.3+."""
30+
return pytest.mark.skipif(IS_GQL_33, reason=reason)
31+
32+
1733
_TESTS_DIR = pathlib.Path(__file__).parent
1834
_ROOT_DIR = _TESTS_DIR.parent
1935

0 commit comments

Comments
 (0)