Skip to content

Commit c8353eb

Browse files
committed
find_breaking_changes: use string representation to compare default values
Replicates graphql/graphql-js@fc0c06c
1 parent ffddea9 commit c8353eb

File tree

5 files changed

+134
-23
lines changed

5 files changed

+134
-23
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ a query language for APIs created by Facebook.
1313
[![Code Style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
1414

1515
The current version 1.0.5 of GraphQL-core-next is up-to-date with GraphQL.js version
16-
14.3.1. All parts of the API are covered by an extensive test suite of currently 1787
16+
14.3.1. All parts of the API are covered by an extensive test suite of currently 1788
1717
unit tests.
1818

1919

graphql/utilities/find_breaking_changes.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
from enum import Enum
2-
from typing import Dict, List, NamedTuple, Union, cast
2+
from typing import Any, Dict, List, NamedTuple, Union, cast
33

44
from ..error import INVALID
5+
from ..language import print_ast
56
from ..pyutils import inspect
67
from ..type import (
78
GraphQLEnumType,
89
GraphQLField,
910
GraphQLList,
1011
GraphQLNamedType,
1112
GraphQLNonNull,
13+
GraphQLInputType,
1214
GraphQLInterfaceType,
1315
GraphQLObjectType,
1416
GraphQLSchema,
@@ -26,6 +28,7 @@
2628
is_scalar_type,
2729
is_union_type,
2830
)
31+
from .ast_from_value import ast_from_value
2932

3033
__all__ = [
3134
"BreakingChange",
@@ -386,17 +389,28 @@ def find_arg_changes(
386389
f" {old_arg.type} to {new_arg.type}.",
387390
)
388391
)
389-
elif (
390-
old_arg.default_value is not INVALID
391-
and old_arg.default_value != new_arg.default_value
392-
):
393-
schema_changes.append(
394-
DangerousChange(
395-
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
396-
f"{old_type.name}.{field_name} arg"
397-
f" {arg_name} has changed defaultValue.",
392+
elif old_arg.default_value is not INVALID:
393+
if new_arg.default_value is INVALID:
394+
schema_changes.append(
395+
DangerousChange(
396+
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
397+
f"{old_type.name}.{field_name} arg"
398+
f" {arg_name} defaultValue was removed.",
399+
)
398400
)
399-
)
401+
else:
402+
old_value_str = stringify_value(old_arg.default_value, old_arg.type)
403+
new_value_str = stringify_value(new_arg.default_value, new_arg.type)
404+
405+
if old_value_str != new_value_str:
406+
schema_changes.append(
407+
DangerousChange(
408+
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
409+
f"{old_type.name}.{field_name} arg"
410+
f" {arg_name} has changed defaultValue"
411+
f" from {old_value_str} to {new_value_str}.",
412+
)
413+
)
400414

401415
for arg_name, new_arg in args_diff.added.items():
402416
if is_required_argument(new_arg):
@@ -514,6 +528,13 @@ def type_kind_name(type_: GraphQLNamedType) -> str:
514528
raise TypeError(f"Unexpected type {inspect(type)}") # pragma: no cover
515529

516530

531+
def stringify_value(value: Any, type_: GraphQLInputType) -> str:
532+
ast = ast_from_value(value, type_)
533+
if ast is None:
534+
raise TypeError(f"Invalid value: {inspect(value)}")
535+
return print_ast(ast)
536+
537+
517538
class ListDiff(NamedTuple):
518539
"""Tuple with added, removed and persisted list items."""
519540

graphql/utilities/introspection_from_schema.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from ..error import GraphQLError
44
from ..language import parse
55
from ..type import GraphQLSchema
6-
from ..utilities.introspection_query import get_introspection_query
6+
from .introspection_query import get_introspection_query
77

88
__all__ = ["introspection_from_schema"]
99

graphql/utilities/type_info.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
is_input_object_type,
4242
is_enum_type,
4343
)
44-
from ..utilities import type_from_ast
44+
from .type_from_ast import type_from_ast
4545

4646
__all__ = ["TypeInfo"]
4747

tests/utilities/test_find_breaking_changes.py

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -823,30 +823,119 @@ def should_detect_locations_removed_from_a_directive():
823823

824824

825825
def describe_find_dangerous_changes():
826-
def should_detect_if_an_arguments_default_value_has_changed():
827-
old_schema = build_schema(
828-
"""
826+
def should_detect_if_a_default_value_changed_on_an_argument():
827+
old_sdl = """
828+
input Input1 {
829+
innerInputArray: [Input2]
830+
}
831+
832+
input Input2 {
833+
arrayField: [Int]
834+
}
835+
829836
type Type1 {
830-
field1(name: String = "test"): String
837+
field1(
838+
withDefaultValue: String = "TO BE DELETED"
839+
stringArg: String = "test"
840+
emptyArray: [Int!] = []
841+
valueArray: [[String]] = [["a", "b"], ["c"]]
842+
complexObject: Input1 = {
843+
innerInputArray: [{ arrayField: [1, 2, 3] }]
844+
}
845+
): String
831846
}
832847
"""
833-
)
848+
849+
old_schema = build_schema(old_sdl)
850+
copy_of_old_schema = build_schema(old_sdl)
851+
assert find_dangerous_changes(old_schema, copy_of_old_schema) == []
834852

835853
new_schema = build_schema(
836854
"""
855+
input Input1 {
856+
innerInputArray: [Input2]
857+
}
858+
859+
input Input2 {
860+
arrayField: [Int]
861+
}
862+
837863
type Type1 {
838-
field1(name: String = "Test"): String
864+
field1(
865+
withDefaultValue: String
866+
stringArg: String = "Test"
867+
emptyArray: [Int!] = [7]
868+
valueArray: [[String]] = [["b", "a"], ["d"]]
869+
complexObject: Input1 = {
870+
innerInputArray: [{ arrayField: [3, 2, 1] }]
871+
}
872+
): String
839873
}
840874
"""
841875
)
842876

843877
assert find_dangerous_changes(old_schema, new_schema) == [
844878
(
845879
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
846-
"Type1.field1 arg name has changed defaultValue.",
847-
)
880+
"Type1.field1 arg withDefaultValue defaultValue was removed.",
881+
),
882+
(
883+
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
884+
"Type1.field1 arg stringArg has changed defaultValue"
885+
' from "test" to "Test".',
886+
),
887+
(
888+
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
889+
"Type1.field1 arg emptyArray has changed defaultValue from [] to [7].",
890+
),
891+
(
892+
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
893+
"Type1.field1 arg valueArray has changed defaultValue"
894+
' from [["a", "b"], ["c"]] to [["b", "a"], ["d"]].',
895+
),
896+
(
897+
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
898+
"Type1.field1 arg complexObject has changed defaultValue"
899+
" from {innerInputArray: [{arrayField: [1, 2, 3]}]}"
900+
" to {innerInputArray: [{arrayField: [3, 2, 1]}]}.",
901+
),
848902
]
849903

904+
def should_ignore_changes_in_field_order_of_default_value():
905+
old_schema = build_schema(
906+
"""
907+
input Input1 {
908+
a: String
909+
b: String
910+
c: String
911+
}
912+
913+
type Type1 {
914+
field1(
915+
arg1: Input1 = { a: "a", b: "b", c: "c" }
916+
): String
917+
}
918+
"""
919+
)
920+
921+
new_schema = build_schema(
922+
"""
923+
input Input1 {
924+
a: String
925+
b: String
926+
c: String
927+
}
928+
929+
type Type1 {
930+
field1(
931+
arg1: Input1 = { c: "c", b: "b", a: "a" }
932+
): String
933+
}
934+
"""
935+
)
936+
937+
assert find_dangerous_changes(old_schema, new_schema) == []
938+
850939
def should_detect_if_a_value_was_added_to_an_enum_type():
851940
old_schema = build_schema(
852941
"""
@@ -999,7 +1088,8 @@ def should_find_all_dangerous_changes():
9991088
),
10001089
(
10011090
DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
1002-
"Type1.field1 arg argThatChangesDefaultValue has changed defaultValue.",
1091+
"Type1.field1 arg argThatChangesDefaultValue has changed defaultValue"
1092+
' from "test" to "Test".',
10031093
),
10041094
(
10051095
DangerousChangeType.INTERFACE_ADDED_TO_OBJECT,

0 commit comments

Comments
 (0)