Skip to content

Commit

Permalink
Merge branch 'main' into remove-django_mptt-replace-with-django_tree_…
Browse files Browse the repository at this point in the history
…queries

Signed-off-by: Kwong Tung Nan <[email protected]>
  • Loading branch information
kwongtn committed Jan 4, 2025
2 parents 8ccd07e + 20f8ef2 commit 82e0f1d
Show file tree
Hide file tree
Showing 19 changed files with 353 additions and 199 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ repos:
- id: check-xml
- id: check-symlinks
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.4
rev: v0.8.5
hooks:
- id: ruff-format
- id: ruff
Expand Down
338 changes: 167 additions & 171 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]
name = "strawberry-graphql-django"
packages = [{ include = "strawberry_django" }]
version = "0.53.0"
version = "0.53.1"
description = "Strawberry GraphQL Django extension"
authors = [
"Lauri Hintsala <[email protected]>",
Expand Down Expand Up @@ -54,7 +54,7 @@ pytest-django = "^4.1.0"
pytest-mock = "^3.5.1"
pytest-snapshot = "^0.9.0"
pytest-watch = "^4.2.0"
ruff = "^0.8.2"
ruff = "^0.8.5"
django-polymorphic = "^3.1.0"
setuptools = "^75.1.0"
psycopg2 = "^2.9.9"
Expand Down
2 changes: 1 addition & 1 deletion strawberry_django/descriptors.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import inspect
from collections.abc import Callable
from typing import (
TYPE_CHECKING,
Any,
Callable,
Generic,
Optional,
TypeVar,
Expand Down
4 changes: 2 additions & 2 deletions strawberry_django/extensions/django_cache_base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections.abc import Hashable
from collections.abc import Callable, Hashable
from functools import _make_key # noqa: PLC2701
from typing import Callable, Optional, cast
from typing import Optional, cast

from django.core.cache import caches
from django.core.cache.backends.base import DEFAULT_TIMEOUT
Expand Down
2 changes: 1 addition & 1 deletion strawberry_django/fields/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from collections.abc import (
AsyncIterable,
AsyncIterator,
Callable,
Iterable,
Iterator,
Mapping,
Expand All @@ -14,7 +15,6 @@
from typing import (
TYPE_CHECKING,
Any,
Callable,
TypeVar,
Union,
cast,
Expand Down
3 changes: 1 addition & 2 deletions strawberry_django/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from typing import (
TYPE_CHECKING,
Any,
Callable,
Generic,
TypeVar,
cast,
Expand Down Expand Up @@ -40,7 +39,7 @@
from .settings import strawberry_django_settings

if TYPE_CHECKING:
from collections.abc import Sequence
from collections.abc import Callable, Sequence
from types import FunctionType

from django.db.models import Model
Expand Down
3 changes: 1 addition & 2 deletions strawberry_django/mutations/mutations.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import dataclasses
from collections.abc import Mapping, Sequence
from collections.abc import Callable, Mapping, Sequence
from typing import (
Any,
Callable,
Optional,
TypeVar,
Union,
Expand Down
3 changes: 1 addition & 2 deletions strawberry_django/mutations/resolvers.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from __future__ import annotations

import dataclasses
from collections.abc import Iterable
from collections.abc import Callable, Iterable
from enum import Enum
from typing import (
TYPE_CHECKING,
Any,
Callable,
TypeVar,
cast,
overload,
Expand Down
7 changes: 6 additions & 1 deletion strawberry_django/optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
import dataclasses
import itertools
from collections import defaultdict
from collections.abc import Callable
from typing import (
TYPE_CHECKING,
Any,
Callable,
TypeVar,
cast,
)
Expand Down Expand Up @@ -1421,6 +1421,11 @@ def __init__(
self.enable_nested_relations_prefetch = enable_nested_relations_prefetch
self.prefetch_custom_queryset = prefetch_custom_queryset

if enable_nested_relations_prefetch:
from strawberry_django.utils.patches import apply_pagination_fix

apply_pagination_fix()

def on_execute(self) -> Generator[None]:
token = optimizer.set(self)
try:
Expand Down
3 changes: 1 addition & 2 deletions strawberry_django/ordering.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import enum
from typing import (
TYPE_CHECKING,
Callable,
Optional,
TypeVar,
cast,
Expand Down Expand Up @@ -32,7 +31,7 @@
from .arguments import argument

if TYPE_CHECKING:
from collections.abc import Collection, Sequence
from collections.abc import Callable, Collection, Sequence

from django.db.models import Model
from strawberry.types import Info
Expand Down
3 changes: 1 addition & 2 deletions strawberry_django/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
import enum
import functools
import inspect
from collections.abc import Hashable, Iterable
from collections.abc import Callable, Hashable, Iterable
from typing import (
TYPE_CHECKING,
Any,
Callable,
ClassVar,
Optional,
TypeVar,
Expand Down
4 changes: 3 additions & 1 deletion strawberry_django/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import contextvars
import functools
import inspect
from typing import TYPE_CHECKING, Any, Callable, TypeVar, overload
from typing import TYPE_CHECKING, Any, TypeVar, overload

from asgiref.sync import sync_to_async
from django.db import models
Expand All @@ -13,6 +13,8 @@
from typing_extensions import ParamSpec

if TYPE_CHECKING:
from collections.abc import Callable

from graphql.pyutils import AwaitableOrValue

_SENTINEL = object()
Expand Down
3 changes: 1 addition & 2 deletions strawberry_django/type.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
import inspect
import sys
import types
from collections.abc import Collection, Sequence
from collections.abc import Callable, Collection, Sequence
from typing import (
Callable,
Generic,
Optional,
TypeVar,
Expand Down
78 changes: 78 additions & 0 deletions strawberry_django/utils/patches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import django
from django.db import (
DEFAULT_DB_ALIAS,
NotSupportedError,
connections,
)
from django.db.models import Q, Window
from django.db.models.fields import related_descriptors
from django.db.models.functions import RowNumber
from django.db.models.lookups import GreaterThan, LessThanOrEqual
from django.db.models.sql import Query
from django.db.models.sql.constants import INNER
from django.db.models.sql.where import AND


def apply_pagination_fix():
"""Apply pagination fix for Django 5.1 or older.
This is based on the fix in this patch, which is going to be included in Django 5.2:
https://code.djangoproject.com/ticket/35677#comment:9
If can safely be removed when Django 5.2 is the minimum version we support
"""
if django.VERSION >= (5, 2):
return

# This is a copy of the function, exactly as it exists on Django 4.2, 5.0 and 5.1
# (there are no differences in this function between these versions)
def _filter_prefetch_queryset(queryset, field_name, instances):
predicate = Q(**{f"{field_name}__in": instances})
db = queryset._db or DEFAULT_DB_ALIAS
if queryset.query.is_sliced:
if not connections[db].features.supports_over_clause:
raise NotSupportedError(
"Prefetching from a limited queryset is only supported on backends "
"that support window functions."
)
low_mark, high_mark = queryset.query.low_mark, queryset.query.high_mark
order_by = [
expr for expr, _ in queryset.query.get_compiler(using=db).get_order_by()
]
window = Window(RowNumber(), partition_by=field_name, order_by=order_by)
predicate &= GreaterThan(window, low_mark)
if high_mark is not None:
predicate &= LessThanOrEqual(window, high_mark)
queryset.query.clear_limits()

# >> ORIGINAL CODE
# return queryset.filter(predicate) # noqa: ERA001
# << ORIGINAL CODE
# >> PATCHED CODE
queryset.query.add_q(predicate, reuse_all_aliases=True)
return queryset
# << PATCHED CODE

related_descriptors._filter_prefetch_queryset = _filter_prefetch_queryset # type: ignore

# This is a copy of the function, exactly as it exists on Django 4.2, 5.0 and 5.1
# (there are no differences in this function between these versions)
def add_q(self, q_object, reuse_all_aliases=False):
existing_inner = {
a for a in self.alias_map if self.alias_map[a].join_type == INNER
}
# >> ORIGINAL CODE
# clause, _ = self._add_q(q_object, self.used_aliases) # noqa: ERA001
# << ORIGINAL CODE
# >> PATCHED CODE
if reuse_all_aliases: # noqa: SIM108
can_reuse = set(self.alias_map)
else:
can_reuse = self.used_aliases
clause, _ = self._add_q(q_object, can_reuse)
# << PATCHED CODE
if clause:
self.where.add(clause, AND)
self.demote_joins(existing_inner)

Query.add_q = add_q
3 changes: 1 addition & 2 deletions strawberry_django/utils/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@

import dataclasses
import sys
from collections.abc import Iterable, Mapping, Sequence
from collections.abc import Callable, Iterable, Mapping, Sequence
from typing import (
TYPE_CHECKING,
Any,
Callable,
ClassVar,
TypeVar,
Union,
Expand Down
10 changes: 8 additions & 2 deletions tests/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,18 @@ class Meta:


class Issue(NamedModel):
comments: "RelatedManager[Issue]"
issue_assignees: "RelatedManager[Assignee]"
class Meta: # type: ignore
ordering = ("id",)

class Kind(models.TextChoices):
"""Issue kind options."""

BUG = "b", "Bug"
FEATURE = "f", "Feature"

comments: "RelatedManager[Issue]"
issue_assignees: "RelatedManager[Assignee]"

id = models.BigAutoField(
verbose_name="ID",
primary_key=True,
Expand Down Expand Up @@ -203,6 +206,9 @@ class Meta:


class Tag(NamedModel):
class Meta: # type: ignore
ordering = ("id",)

issues: "RelatedManager[Issue]"

id = models.BigAutoField(
Expand Down
4 changes: 2 additions & 2 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def test_django_export_schema():
def test_django_export_schema_exception_handle():
with pytest.raises(
CommandError,
match="No module named 'tests.fake_schema'",
match=r"No module named 'tests.fake_schema'",
):
call_command("export_schema", "tests.fake_schema")

Expand All @@ -40,7 +40,7 @@ def test_django_export_schema_exception_handle():
mock_import_module,
pytest.raises(
CommandError,
match="The `schema` must be an instance of strawberry.Schema",
match=r"The `schema` must be an instance of strawberry.Schema",
),
):
call_command("export_schema", "tests.schema")
Loading

0 comments on commit 82e0f1d

Please sign in to comment.