strawberry-graphql / strawberry-django

Strawberry GraphQL Django extension
https://strawberry.rocks/docs/django
MIT License
415 stars 120 forks source link

Strawberry Django Plus migration problem: get_queryset in mutations #316

Closed iamcrookedman closed 1 year ago

iamcrookedman commented 1 year ago

The behavior for the method resolve_node_sync was broken after migration and it doesn't call get_queryset method anymore.

For example, I have this code in mutation: instance = input_data["id"].resolve_node_sync(info=info)

Get queryset method in type:

@classmethod
def get_queryset(cls, queryset: BaseModelAvailableQuerySet, info: Info, **kwargs) -> BaseModelAvailableQuerySet:
    return queryset.filter_available(user=info.context.request.user)

Now this code can't be used because resolve_model_node was changed.

How it was:

def resolve_model_node(source, node_id, *, info: Optional[Info] = None, required=False):
    if issubclass(source, Model):
        origin = None
    else:
        origin = source
        django_type = get_django_type(source, ensure_type=True)
        source = cast(Type[Model], django_type.model)

    if isinstance(node_id, relay.GlobalID):
        node_id = node_id.node_id

    id_attr = cast(relay.Node, origin).resolve_id_attr()

    qs = source._default_manager.filter(**{id_attr: node_id})

    if origin and hasattr(origin, "get_queryset"):
        qs = origin.get_queryset(qs, info)

    return resolve_result(
        qs,
        info=info,
        qs_resolver=resolve_qs_get_one if required else resolve_qs_get_first,
    )

How it's now:

def resolve_model_node(
    source,
    node_id,
    *,
    info: Optional[Info] = None,
    required=False,
    filter_perms=False,
):
    from strawberry_django import optimizer  # avoid circular import
    from strawberry_django.permissions import filter_with_perms

    if issubclass(source, models.Model):
        origin = None
    else:
        origin = source
        django_type = get_django_definition(source, strict=True)
        source = cast(Type[models.Model], django_type.model)

    if isinstance(node_id, relay.GlobalID):
        node_id = node_id.node_id

    id_attr = cast(relay.Node, origin).resolve_id_attr()
    qs = source._default_manager.filter(**{id_attr: node_id})

    if info is not None:
        if filter_perms:
            qs = filter_with_perms(qs, info)

        ext = optimizer.optimizer.get()
        if ext is not None:
            # If optimizer extension is enabled, optimize this queryset
            qs = ext.optimize(qs, info=info)

    return django_resolver(lambda: qs.get() if required else qs.first())()

Upvote & Fund

Fund with Polar

iamcrookedman commented 1 year ago

This is very critical from a backwards compatibility point of view.

iamcrookedman commented 1 year ago

Thank you!