Skip to content
Open
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
6 changes: 6 additions & 0 deletions graphene_federation/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
build_schema as build_directive_schema,
directive_decorator,
)
from graphene_directives import utils as graphene_directives_utils
from graphene_directives.schema import Schema

from .apollo_versions import (
Expand Down Expand Up @@ -53,6 +54,11 @@ def _add_sharable_to_page_info_type(
try:
# PageInfo needs @sharable directive
sharable = get_directive_from_name("shareable", federation_version)
if graphene_directives_utils.has_non_field_attribute(
page_info.graphene_type, sharable
):
# already added, skip
return
types.append(
directive_decorator(target_directive=sharable)(field=None)(
page_info.graphene_type
Expand Down
28 changes: 27 additions & 1 deletion tests/test_shareable.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import graphene
import pytest
from graphene import ObjectType
from graphene import ObjectType, relay
from graphene_directives import DirectiveValidationError

from graphene_federation import LATEST_VERSION, build_schema
Expand Down Expand Up @@ -90,3 +90,29 @@ class Query(ObjectType):
)

assert "@shareable cannot be used for SearchResult" in str(err.value)


def test_add_sharable_to_page_info_type_idempotent():
"""
build_schema must not raise DirectiveValidationError when called multiple times
with a schema that includes PageInfo (e.g. via relay connections).
_add_sharable_to_page_info_type mutates the global PageInfo class in-place,
so a second call would previously attempt to apply @shareable again and crash.
"""

class Item(graphene.ObjectType):
class Meta:
interfaces = (relay.Node,)

name = graphene.String()

class ItemConnection(relay.Connection):
class Meta:
node = Item

class Query(ObjectType):
items = relay.ConnectionField(ItemConnection)

build_schema(query=Query, federation_version=LATEST_VERSION)
# Second call must not raise DirectiveValidationError
build_schema(query=Query, federation_version=LATEST_VERSION)