1
+ from graphql import build_schema , GraphQLType , is_non_null_type , is_list_type , is_scalar_type , is_enum_type , \
2
+ is_input_object_type , is_object_type , is_interface_type , is_introspection_type , GraphQLSchema
3
+
4
+
5
+ def is_equals_schema (schema_a : GraphQLSchema , schema_b : GraphQLSchema ):
6
+ """
7
+ Check to schemas are equivalent.
8
+
9
+ TODO:
10
+ - Compare directive definitions
11
+ - Check field directives
12
+
13
+ :param schema_a:
14
+ :param schema_b:
15
+ :return:
16
+ """
17
+ # check set of named types
18
+ types_a = set ([n for n , t in schema_a .type_map .items () if not is_introspection_type (t )])
19
+ types_b = set ([n for n , t in schema_b .type_map .items () if not is_introspection_type (t )])
20
+ if types_a != types_b :
21
+ return False
22
+
23
+ # check all named types
24
+ types = types_a
25
+ for type_name in types :
26
+ if not is_equal_type (schema_a .type_map [type_name ], schema_b .type_map [type_name ]):
27
+ return False
28
+
29
+ return True
30
+
31
+
32
+ def is_equal_type (type_a : GraphQLType , type_b : GraphQLType ):
33
+ """Check whether two GraphQL types are equivalent."""
34
+ # Check GraphQL base types
35
+ if is_non_null_type (type_a ) != is_non_null_type (type_b ):
36
+ return False
37
+ if is_list_type (type_a ) != is_list_type (type_b ):
38
+ return False
39
+ if is_input_object_type (type_a ) != is_input_object_type (type_b ):
40
+ return False
41
+ if is_object_type (type_a ) != is_object_type (type_b ):
42
+ return False
43
+ if is_enum_type (type_a ) != is_enum_type (type_b ):
44
+ return False
45
+ if is_scalar_type (type_a ) != is_scalar_type (type_b ):
46
+ return False
47
+ if is_interface_type (type_a ) != is_interface_type (type_b ):
48
+ return False
49
+
50
+ # If either type is non-null, the other must also be non-null.
51
+ if is_non_null_type (type_a ) and is_non_null_type (type_b ):
52
+ return is_equal_type (type_a .of_type , type_b .of_type )
53
+
54
+ # If either type is a list, the other must also be a list.
55
+ if is_list_type (type_a ):
56
+ return is_equal_type (type_a .of_type , type_b .of_type )
57
+
58
+ # Check name
59
+ if type_a .name != type_b .name :
60
+ return False
61
+
62
+ # If scalar then done
63
+ if is_scalar_type (type_a ):
64
+ return True
65
+
66
+ # If enum then check values
67
+ if is_enum_type (type_a ):
68
+ # TODO compare values
69
+ return
70
+
71
+ # if not interface, check interfaces
72
+ if not is_input_object_type (type_a ) and not is_interface_type (type_a ):
73
+ interfaces_a = set ([i .name for i in type_a .interfaces ])
74
+ interfaces_b = set ([i .name for i in type_b .interfaces ])
75
+ if interfaces_a != interfaces_b :
76
+ return False
77
+
78
+ # Check fields
79
+ # 1) Field names
80
+ field_names_a = set ([i for i in type_a .fields ])
81
+ field_names_b = set ([i for i in type_b .fields ])
82
+ if field_names_a != field_names_b :
83
+ return False
84
+ # 2) Field types
85
+ field_names = field_names_a
86
+ for field_name in field_names :
87
+ if not is_equal_type (type_a .fields [field_name ].type , type_b .fields [field_name ].type ):
88
+ return False
89
+ # 3) Field argument names and types
90
+ for field_name in field_names :
91
+ arg_names_a = set ([i for i in type_a .fields [field_name ].args ])
92
+ arg_names_b = set ([i for i in type_b .fields [field_name ].args ])
93
+ if arg_names_a != arg_names_b :
94
+ return False
95
+ arg_names = arg_names_a
96
+ for arg_name in arg_names :
97
+ arg_type_a = type_a .fields [field_name ].args [arg_name ].type
98
+ arg_type_b = type_b .fields [field_name ].args [arg_name ].type
99
+ if not is_equal_type (arg_type_a , arg_type_b ):
100
+ return False
101
+
102
+ # TODO: check field directives
103
+
104
+ return True
0 commit comments