1
- from operator import attrgetter
2
- from typing import Collection , Dict , List , cast
1
+ from typing import Dict , List , Tuple , cast
3
2
4
3
from ..type import (
5
4
GraphQLArgument ,
24
23
is_non_null_type ,
25
24
is_object_type ,
26
25
is_scalar_type ,
27
- is_specified_scalar_type ,
28
26
is_union_type ,
29
27
)
30
28
34
32
def lexicographic_sort_schema (schema : GraphQLSchema ) -> GraphQLSchema :
35
33
"""Sort GraphQLSchema."""
36
34
37
- cache : Dict [str , GraphQLNamedType ] = {}
35
+ def replace_type (type_ ):
36
+ if is_list_type (type_ ):
37
+ return GraphQLList (replace_type (type_ .of_type ))
38
+ elif is_non_null_type (type_ ):
39
+ return GraphQLNonNull (replace_type (type_ .of_type ))
40
+ else :
41
+ return replace_named_type (type_ )
42
+
43
+ def replace_named_type (type_ : GraphQLNamedType ) -> GraphQLNamedType :
44
+ return type_map [type_ .name ]
38
45
39
- def sort_maybe_type (maybe_type ):
40
- return maybe_type and sort_named_type (maybe_type )
46
+ def replace_maybe_type (maybe_type ):
47
+ return maybe_type and replace_named_type (maybe_type )
41
48
42
49
def sort_directive (directive ):
43
50
kwargs = directive .to_kwargs ()
44
51
kwargs .update (
45
- locations = sorted (directive .locations , key = attrgetter ( "name" ) ),
52
+ locations = sorted (directive .locations , key = sort_by_name_key ),
46
53
args = sort_args (directive .args ),
47
54
)
48
55
return GraphQLDirective (** kwargs )
@@ -51,58 +58,43 @@ def sort_args(args_map):
51
58
args = {}
52
59
for name , arg in sorted (args_map .items ()):
53
60
kwargs = arg .to_kwargs ()
54
- kwargs .update (type_ = sort_type (arg .type ))
61
+ kwargs .update (type_ = replace_type (arg .type ))
55
62
args [name ] = GraphQLArgument (** kwargs )
56
63
return args
57
64
58
65
def sort_fields (fields_map ):
59
66
fields = {}
60
67
for name , field in sorted (fields_map .items ()):
61
68
kwargs = field .to_kwargs ()
62
- kwargs .update (type_ = sort_type (field .type ), args = sort_args (field .args ))
69
+ kwargs .update (type_ = replace_type (field .type ), args = sort_args (field .args ))
63
70
fields [name ] = GraphQLField (** kwargs )
64
71
return fields
65
72
66
73
def sort_input_fields (fields_map ):
67
74
return {
68
75
name : GraphQLInputField (
69
- sort_type (field .type ),
76
+ replace_type (field .type ),
70
77
description = field .description ,
71
78
default_value = field .default_value ,
72
79
ast_node = field .ast_node ,
73
80
)
74
81
for name , field in sorted (fields_map .items ())
75
82
}
76
83
77
- def sort_type (type_ ):
78
- if is_list_type (type_ ):
79
- return GraphQLList (sort_type (type_ .of_type ))
80
- elif is_non_null_type (type_ ):
81
- return GraphQLNonNull (sort_type (type_ .of_type ))
82
- else :
83
- return sort_named_type (type_ )
84
+ def sort_types (arr : List [GraphQLNamedType ]) -> List [GraphQLNamedType ]:
85
+ return [
86
+ replace_named_type (type_ ) for type_ in sorted (arr , key = sort_by_name_key )
87
+ ]
84
88
85
89
def sort_named_type (type_ : GraphQLNamedType ) -> GraphQLNamedType :
86
- if is_specified_scalar_type (type_ ) or is_introspection_type (type_ ):
87
- return type_
88
-
89
- sorted_type = cache .get (type_ .name )
90
- if not sorted_type :
91
- sorted_type = sort_named_type_impl (type_ )
92
- cache [type_ .name ] = sorted_type
93
- return sorted_type
94
-
95
- def sort_types (arr : Collection [GraphQLNamedType ]) -> List [GraphQLNamedType ]:
96
- return [sort_named_type (type_ ) for type_ in sorted (arr , key = attrgetter ("name" ))]
97
-
98
- def sort_named_type_impl (type_ : GraphQLNamedType ) -> GraphQLNamedType :
99
- if is_scalar_type (type_ ):
90
+ if is_scalar_type (type_ ) or is_introspection_type (type_ ):
100
91
return type_
101
92
elif is_object_type (type_ ):
102
93
kwargs = type_ .to_kwargs ()
103
94
object_type = cast (GraphQLObjectType , type_ )
95
+ # noinspection PyTypeChecker
104
96
kwargs .update (
105
- interfaces = lambda : sort_types (object_type .interfaces ),
97
+ interfaces = lambda : sort_types (object_type .interfaces ), # type: ignore
106
98
fields = lambda : sort_fields (object_type .fields ),
107
99
)
108
100
return GraphQLObjectType (** kwargs )
@@ -114,7 +106,8 @@ def sort_named_type_impl(type_: GraphQLNamedType) -> GraphQLNamedType:
114
106
elif is_union_type (type_ ):
115
107
kwargs = type_ .to_kwargs ()
116
108
union_type = cast (GraphQLUnionType , type_ )
117
- kwargs .update (types = lambda : sort_types (union_type .types ))
109
+ # noinspection PyTypeChecker
110
+ kwargs .update (types = lambda : sort_types (union_type .types )) # type: ignore
118
111
return GraphQLUnionType (** kwargs )
119
112
elif is_enum_type (type_ ):
120
113
kwargs = type_ .to_kwargs ()
@@ -134,18 +127,29 @@ def sort_named_type_impl(type_: GraphQLNamedType) -> GraphQLNamedType:
134
127
elif is_input_object_type (type_ ):
135
128
kwargs = type_ .to_kwargs ()
136
129
input_object_type = cast (GraphQLInputObjectType , type_ )
137
- kwargs .update (fields = sort_input_fields (input_object_type .fields ))
130
+ kwargs .update (fields = lambda : sort_input_fields (input_object_type .fields ))
138
131
return GraphQLInputObjectType (** kwargs )
139
132
raise TypeError (f"Unknown type: '{ type_ } '" )
140
133
134
+ type_map : Dict [str , GraphQLNamedType ] = {
135
+ type_ .name : sort_named_type (type_ )
136
+ for type_ in sorted (schema .type_map .values (), key = sort_by_name_key )
137
+ }
138
+
141
139
return GraphQLSchema (
142
- types = sort_types ( schema . type_map .values ()),
140
+ types = list ( type_map .values ()),
143
141
directives = [
144
142
sort_directive (directive )
145
- for directive in sorted (schema .directives , key = attrgetter ( "name" ) )
143
+ for directive in sorted (schema .directives , key = sort_by_name_key )
146
144
],
147
- query = sort_maybe_type (schema .query_type ),
148
- mutation = sort_maybe_type (schema .mutation_type ),
149
- subscription = sort_maybe_type (schema .subscription_type ),
145
+ query = replace_maybe_type (schema .query_type ),
146
+ mutation = replace_maybe_type (schema .mutation_type ),
147
+ subscription = replace_maybe_type (schema .subscription_type ),
150
148
ast_node = schema .ast_node ,
151
149
)
150
+
151
+
152
+ def sort_by_name_key (type_ ) -> Tuple [bool , str ]:
153
+ name = type_ .name
154
+ # GraphQL.JS sorts '_' first using localeCompare
155
+ return not name .startswith ("_" ), name
0 commit comments