Skip to content

Commit fa019c3

Browse files
committed
Working on the new printing for API schemas
1 parent 8f3240f commit fa019c3

File tree

2 files changed

+214
-7
lines changed

2 files changed

+214
-7
lines changed

graphql-api-generator/generator.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,16 @@ def cmd(args):
3636
with open(file, 'r') as f:
3737
schema_string += f.read() + '\n'
3838
schema = build_schema(schema_string)
39-
39+
4040
# run
4141
schema = run(schema, config)
4242

4343
# write to file or stdout
4444
if args.output:
4545
with open(args.output, 'w') as out:
46-
out.write(print_schema(schema))
46+
out.write(printSchemaWithDirectives(schema))
4747
else:
48-
print(print_schema(schema))
48+
print(printSchemaWithDirectives(schema))
4949

5050

5151
def run(schema: GraphQLSchema, config: dict):
@@ -138,7 +138,7 @@ def run(schema: GraphQLSchema, config: dict):
138138
raise UnsupportedOperation('{0} is currently not supported'.format('delete_edge_objects'))
139139

140140
# remove field arguments for edges (should not be in the API schema)
141-
schema = remove_field_arguments_for_types(schema)
141+
#schema = remove_field_arguments_for_types(schema)
142142

143143
return schema
144144

graphql-api-generator/utils/utils.py

Lines changed: 210 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,14 +202,27 @@ def add_reverse_edges(schema: GraphQLSchema):
202202
# Reverse edge
203203
edge_from = get_named_type(field_type.type)
204204
edge_name = f'_{field_name}From{_type.name}'
205-
edge_to = GraphQLList(_type)
205+
206+
directives = {}
207+
directive_to_add = ''
208+
209+
if hasattr(field_type, 'ast_node') and field_type.ast_node is not None:
210+
directives = {directive.name.value: directive for directive in field_type.ast_node.directives}
211+
212+
if 'requiredForTarget' in directives:
213+
directive_to_add = '@required'
214+
215+
if 'uniqueForTarget' in directives:
216+
edge_to = _type
217+
else:
218+
edge_to = GraphQLList(_type)
206219

207220
if is_interface_type(edge_from):
208-
make += 'extend interface {0} {{ {1}: {2} }}\n'.format(edge_from, edge_name, edge_to)
221+
make += 'extend interface {0} {{ {1}: {2} {3} }}\n'.format(edge_from, edge_name, edge_to, directive_to_add)
209222
for implementing_type in schema.get_possible_types(edge_from):
210223
make += 'extend type {0} {{ {1}: {2} }}\n'.format(implementing_type, edge_name, edge_to)
211224
else:
212-
make += 'extend type {0} {{ {1}: {2} }}\n'.format(edge_from, edge_name, edge_to)
225+
make += 'extend type {0} {{ {1}: {2} {3} }}\n'.format(edge_from, edge_name, edge_to, directive_to_add)
213226
schema = add_to_schema(schema, make)
214227

215228
return schema
@@ -751,3 +764,197 @@ def add_delete_mutations(schema: GraphQLSchema):
751764
make += f'extend type Mutation {{ {delete}(id: ID!): {_type.name} }} '
752765
schema = add_to_schema(schema, make)
753766
return schema
767+
768+
769+
def ast_type_to_string(_type: GraphQLType):
770+
"""
771+
Print the ast_type properly
772+
:param _type:
773+
:return:
774+
"""
775+
776+
# ast_nodes types behavies differnetly than for other types (as they are NodeTypes)
777+
# So we can't use the normal functions
778+
779+
780+
_post_str = ''
781+
_pre_str = ''
782+
# A, A!, [A!], [A]!, [A!]!
783+
wrappers = []
784+
if isinstance(_type, NonNullTypeNode):
785+
_post_str = '!'
786+
_type = _type.type
787+
if isinstance(_type, ListTypeNode):
788+
_post_str = ']' + _post_str
789+
_pre_str = '['
790+
_type = _type.type
791+
if isinstance(_type, NonNullTypeNode):
792+
_post_str = '!' + _post_str
793+
_type = _type.type
794+
795+
# Dig down to find the actual named node, should be the first one actually
796+
name = _type
797+
while not isinstance(name, NamedTypeNode):
798+
name = name.type
799+
name = name.name.value
800+
801+
return _pre_str + name + _post_str
802+
803+
804+
def directive_from_interface(directive, interface_name):
805+
"""
806+
Return the correct directive string fro directives inhertied from interfaces
807+
:param directive:
808+
:param interface_name:
809+
:return string:
810+
"""
811+
directive_string = directive.name.value
812+
813+
# The only two cases who needs special attention is @requiredForTarget and @uniqueForTarget
814+
if directive_string == 'requiredForTarget':
815+
directive_string = '_requiredForTarget_AccordingToInterface(interface: "' + interface_name + '")'
816+
elif directive_string == 'uniqueForTarget':
817+
directive_string = '_uniqueForTarget_AccordingToInterface(interface: "' + interface_name + '")'
818+
else:
819+
directive_string += get_directive_arguments(directive)
820+
821+
return directive_string
822+
823+
824+
def get_directive_arguments(directive):
825+
"""
826+
Get the arguments of the given directive as string
827+
:param directive:
828+
:return string:
829+
"""
830+
831+
output = ''
832+
if len(directive.arguments) > 0:
833+
output+= '('
834+
for arg in directive.arguments:
835+
output+= arg.name.value + ':'
836+
if isinstance(arg.value, ListValueNode):
837+
output+= '['
838+
for V in arg.value.values:
839+
if isinstance(V, StringValueNode):
840+
output+='"' + V.value + '", '
841+
else:
842+
output+= V.value + ', '
843+
844+
output = output[:-2] + ']'
845+
846+
else:
847+
if isinstance(arg.value, StringValueNode):
848+
output+='"' + arg.value.value + '", '
849+
else:
850+
output+= arg.value.value + ', '
851+
852+
output += ', '
853+
854+
output = output[:-2] + ')'
855+
856+
return output
857+
858+
859+
def printSchemaWithDirectives(schema):
860+
861+
output = ''
862+
863+
for _dir in schema.directives:
864+
if _dir.ast_node is not None:
865+
# If the directive does not have a proper ast_node
866+
# Then it is an non-user defined directive, and can hence, be skipped
867+
output+= 'directive @' + _dir.name
868+
869+
if len(_dir.ast_node.arguments) > 0:
870+
output+= '('
871+
for arg in _dir.ast_node.arguments:
872+
output+= arg.name.value + ': ' + ast_type_to_string(arg.type) + ', '
873+
output = output[:-2] + ')'
874+
875+
output+= ' on '
876+
for _location in _dir.locations:
877+
output+= _location._name_ + ', '
878+
879+
output = output[:-2] + '\n\n'
880+
881+
882+
output += 'directive @_requiredForTarget_AccordingToInterface(interface: String!) on FIELD_DEFINITION\n\n'
883+
output += 'directive @_uniqueForTarget_AccordingToInterface(interface: String!) on FIELD_DEFINITION\n\n'
884+
885+
886+
for _type in sorted(schema.type_map.values(), key=lambda x : x.name):
887+
if _type.name[:2] == '__':
888+
continue
889+
890+
if is_interface_type(_type):
891+
output += 'interface ' + _type.name
892+
elif is_enum_type(_type):
893+
output += 'enum ' + _type.name
894+
elif is_scalar_type(_type):
895+
if _type.ast_node is not None:
896+
# If the scalar does not have a proper ast_node
897+
# Then it is an non-user defined scalar, and can hence, be skipped
898+
output += 'scalar ' + _type.name
899+
elif is_input_type(_type):
900+
output += 'input ' + _type.name
901+
else: # type, hopefully
902+
output += 'type ' + _type.name
903+
if hasattr(_type, 'interfaces') and len(_type.interfaces) > 0:
904+
output += ' implements '
905+
for interface in _type.interfaces:
906+
output += interface.name + ', '
907+
output = output[:-2]
908+
909+
if is_enum_type(_type):
910+
output += ' {\n'
911+
for value in _type.values:
912+
output += ' ' + value + '\n'
913+
output += '}'
914+
915+
elif not is_enum_or_scalar(_type):
916+
if _type.ast_node is not None:
917+
for directive in _type.ast_node.directives:
918+
output+= ' @' + directive.name.value
919+
output += get_directive_arguments(directive)
920+
921+
output += ' {\n'
922+
923+
for field_name, field in _type.fields.items():
924+
output += ' ' + field_name
925+
926+
if hasattr(field, 'args') and field.args:
927+
output += '('
928+
for arg_name, arg in field.args.items():
929+
output += arg_name + ': ' + str(arg.type) + ', '
930+
output = output[:-2] + ')'
931+
932+
output += ': ' + str(field.type)
933+
934+
directives_set = set()
935+
936+
for directive in field.ast_node.directives:
937+
if not directive.name.value in directives_set:
938+
output+= ' @' + directive.name.value
939+
directives_set.add(directive.name.value)
940+
output += get_directive_arguments(directive)
941+
942+
943+
if hasattr(_type, 'interfaces'):
944+
for interface in _type.interfaces:
945+
if field_name in interface.fields:
946+
for directive in interface.fields[field_name].ast_node.directives:
947+
directive_str = directive_from_interface(directive, interface.name)
948+
if not directive_str in directives_set:
949+
output+= ' @' + directive_str
950+
directives_set.add(directive_str)
951+
952+
953+
output += '\n'
954+
955+
output += '}'
956+
957+
if _type.ast_node is not None:
958+
output += '\n\n'
959+
960+
return output

0 commit comments

Comments
 (0)