Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions graphene_django/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,17 +143,30 @@ def connection_resolver(
enforce_first_or_last,
root,
info,
**args
**kwargs
):
first = args.get("first")
last = args.get("last")

if enforce_first_or_last:
assert first or last, (
"You must provide a `first` or `last` value to properly paginate the `{}` connection."
).format(info.field_name)
first = kwargs.get("first")
last = kwargs.get("last")
if first is not None and first <= 0:
raise ValueError(
"`first` argument must be positive, got `{first}`".format(first=first)
)
if last is not None and last <= 0:
raise ValueError(
"`last` argument must be positive, got `{last}`".format(last=last)
)
if enforce_first_or_last and not (first or last):
raise ValueError(
"You must provide a `first` or `last` value "
"to properly paginate the `{info.field_name}` connection.".format(
info=info
)
)

if max_limit:
if first is None and last is None:
kwargs['first'] = first = max_limit

if first:
assert first <= max_limit, (
"Requesting {} records on the `{}` connection exceeds the `first` limit of {} records."
Expand All @@ -165,16 +178,20 @@ def connection_resolver(
"Requesting {} records on the `{}` connection exceeds the `last` limit of {} records."
).format(last, info.field_name, max_limit)
args["last"] = min(last, max_limit)

# eventually leads to DjangoObjectType's get_queryset (accepts queryset)
# or a resolve_foo (does not accept queryset)
iterable = resolver(root, info, **args)

else:
count = min(i for i in (first, last) if i)
if count > max_limit:
raise ValueError(("Requesting {count} records "
"on the `{info.field_name}` connection "
"exceeds the limit of {max_limit} records.").format(
count=count, info=info, max_limit=max_limit))

iterable = resolver(root, info, **kwargs)
if iterable is None:
iterable = default_manager
# thus the iterable gets refiltered by resolve_queryset
# but iterable might be promise
iterable = queryset_resolver(connection, iterable, info, args)
on_resolve = partial(cls.resolve_connection, connection, args)
queryset = cls.resolve_queryset(connection, iterable, info, kwargs)
on_resolve = partial(cls.resolve_connection, connection, queryset, kwargs)

if Promise.is_thenable(iterable):
return Promise.resolve(iterable).then(on_resolve)
Expand Down
39 changes: 38 additions & 1 deletion graphene_django/filter/tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -978,7 +978,7 @@ class Query(ObjectType):
}
}
}
"""
"""
% reporter_1.email
)

Expand All @@ -999,3 +999,40 @@ class Query(ObjectType):

assert not result.errors
assert result.data == expected


def test_filter_with_union():
class ReporterType(DjangoObjectType):
class Meta:
model = Reporter
interfaces = (Node,)
filter_fields = ("first_name",)

class Query(ObjectType):
all_reporters = DjangoFilterConnectionField(ReporterType)

@classmethod
def resolve_all_reporters(cls, root, info, **kwargs):
ret = Reporter.objects.none() | Reporter.objects.filter(first_name="John")

Reporter.objects.create(first_name="John", last_name="Doe")

schema = Schema(query=Query)

query = """
query NodeFilteringQuery {
allReporters(firstName: "abc") {
edges {
node {
firstName
}
}
}
}
"""
expected = {"allReporters": {"edges": []}}

result = schema.execute(query)

assert not result.errors
assert result.data == expected
189 changes: 180 additions & 9 deletions graphene_django/tests/test_query.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import base64
import datetime

import graphene
import pytest
from django.db import models
from django.utils.functional import SimpleLazyObject
from py.test import raises

from django.db.models import Q

from graphql_relay import to_global_id
import graphene
from django.utils.functional import SimpleLazyObject
from graphene.relay import Node
from py.test import raises

from ..utils import DJANGO_FILTER_INSTALLED
from ..compat import MissingType, JSONField
from ..compat import JSONField, MissingType
from ..fields import DjangoConnectionField
from ..types import DjangoObjectType
from ..settings import graphene_settings
from .models import Article, CNNReporter, Reporter, Film, FilmDetails
from ..types import DjangoObjectType
from ..utils import DJANGO_FILTER_INSTALLED
from .models import Article, CNNReporter, Film, FilmDetails, Reporter

pytestmark = pytest.mark.django_db

Expand Down Expand Up @@ -663,7 +663,7 @@ class Query(graphene.ObjectType):
assert len(result.errors) == 1
assert str(result.errors[0]) == (
"Requesting 101 records on the `allReporters` connection "
"exceeds the `first` limit of 100 records."
"exceeds the limit of 100 records."
)
assert result.data == expected

Expand Down Expand Up @@ -706,13 +706,184 @@ class Query(graphene.ObjectType):
assert len(result.errors) == 1
assert str(result.errors[0]) == (
"Requesting 101 records on the `allReporters` connection "
"exceeds the `last` limit of 100 records."
"exceeds the limit of 100 records."
)
assert result.data == expected

graphene_settings.RELAY_CONNECTION_ENFORCE_FIRST_OR_LAST = False


def test_should_not_error_if_last_and_first_not_greater_than_max():
graphene_settings.RELAY_CONNECTION_MAX_LIMIT = 1

class ReporterType(DjangoObjectType):
class Meta:
model = Reporter
interfaces = (Node,)

class Query(graphene.ObjectType):
all_reporters = DjangoConnectionField(ReporterType)

r = Reporter.objects.create(
first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1
)

schema = graphene.Schema(query=Query)
query = """
query NodeFilteringQuery {
allReporters(first: 999999, last: 1) {
edges {
node {
id
}
}
}
}
"""

expected = {"allReporters": {"edges": [{"node": {"id": "UmVwb3J0ZXJUeXBlOjE="}}]}}

result = schema.execute(query)
assert not result.errors
assert result.data == expected

graphene_settings.RELAY_CONNECTION_MAX_LIMIT = 100


def test_should_error_if_negative_first():
class ReporterType(DjangoObjectType):
class Meta:
model = Reporter
interfaces = (Node,)

class Query(graphene.ObjectType):
all_reporters = DjangoConnectionField(ReporterType)

schema = graphene.Schema(query=Query)
query = """
query NodeFilteringQuery {
allReporters(first: -100, last: 200) {
edges {
node {
id
}
}
}
}
"""

expected = {"allReporters": None}

result = schema.execute(query)
assert len(result.errors) == 1
assert str(result.errors[0]) == "`first` argument must be positive, got `-100`"
assert result.data == expected


def test_should_error_if_negative_last():
class ReporterType(DjangoObjectType):
class Meta:
model = Reporter
interfaces = (Node,)

class Query(graphene.ObjectType):
all_reporters = DjangoConnectionField(ReporterType)

schema = graphene.Schema(query=Query)
query = """
query NodeFilteringQuery {
allReporters(first: 200, last: -100) {
edges {
node {
id
}
}
}
}
"""

expected = {"allReporters": None}

result = schema.execute(query)
assert len(result.errors) == 1
assert str(result.errors[0]) == "`last` argument must be positive, got `-100`"
assert result.data == expected


def test_max_limit_is_zero():
graphene_settings.RELAY_CONNECTION_MAX_LIMIT = 0

class ReporterType(DjangoObjectType):
class Meta:
model = Reporter
interfaces = (Node,)

class Query(graphene.ObjectType):
all_reporters = DjangoConnectionField(ReporterType)

r = Reporter.objects.create(
first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1
)

schema = graphene.Schema(query=Query)
query = """
query NodeFilteringQuery {
allReporters(first: 99999999) {
edges {
node {
id
}
}
}
}
"""

expected = {"allReporters": {"edges": [{"node": {"id": "UmVwb3J0ZXJUeXBlOjE="}}]}}

result = schema.execute(query)
assert not result.errors
assert result.data == expected

graphene_settings.RELAY_CONNECTION_MAX_LIMIT = 100


def test_max_limit_is_none():
graphene_settings.RELAY_CONNECTION_MAX_LIMIT = None

class ReporterType(DjangoObjectType):
class Meta:
model = Reporter
interfaces = (Node,)

class Query(graphene.ObjectType):
all_reporters = DjangoConnectionField(ReporterType)

r = Reporter.objects.create(
first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1
)

schema = graphene.Schema(query=Query)
query = """
query NodeFilteringQuery {
allReporters(first: 99999999) {
edges {
node {
id
}
}
}
}
"""

expected = {"allReporters": {"edges": [{"node": {"id": "UmVwb3J0ZXJUeXBlOjE="}}]}}

result = schema.execute(query)
assert not result.errors
assert result.data == expected

graphene_settings.RELAY_CONNECTION_MAX_LIMIT = 100


def test_should_query_promise_connectionfields():
from promise import Promise

Expand Down