Skip to content

Commit 0e1adbf

Browse files
epii-1keski
andauthored
Unions (#97)
* Started work on unions * First crude draft of unions * Minor correction * Reverted #67 * Added error for connecting to union * Implemented fragmenting for unions and corrected some bugs * Update config.yml * update changelog Co-authored-by: Robin Keskisärkkä <[email protected]>
1 parent 42296ee commit 0e1adbf

File tree

8 files changed

+94
-52
lines changed

8 files changed

+94
-52
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
**v0.1.4, to be released on ???**
2+
* New feature: Add support for unions. See: https://github.com/LiUGraphQL/woo.sh/issues/95
23

34
**v0.1.3, released on August 28, 2020**
45
* New feature: Support for multiple *dependent* mutation operations within a single mutation request; https://github.com/LiUGraphQL/woo.sh/issues/52

example/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ generation:
1919
# add reverse edges for traversal
2020
reverse_edges: true
2121
# add edge types
22-
edge_types: false
23-
fields_for_edge_types: false
22+
edge_types: true
23+
fields_for_edge_types: true
2424
# add queries
2525
query_by_id: true
2626
query_type_filter: true

example/db-schema/starwars-db.graphql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
directive @key(fields: [String!]!) on OBJECT
22

3+
union PlanetAndSpecies = Planet | Species
4+
5+
36
enum Episode {
47
NEWHOPE
58
EMPIRE
@@ -46,4 +49,5 @@ type Species {
4649
type Starship {
4750
name: String!
4851
length: Float
52+
style: PlanetAndSpecies
4953
}

graphql-api-generator/generator.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def validate_names(schema: GraphQLSchema, validate):
170170
if f is None:
171171
raise Exception('Unrecognized option: ' + validate.get('field_names'))
172172
for type_name, _type in schema.type_map.items():
173-
if is_introspection_type(_type) or is_enum_or_scalar(_type):
173+
if is_introspection_type(_type) or is_enum_or_scalar(_type) or is_union_type(_type):
174174
continue
175175
for field_name in _type.fields.keys():
176176
if field_name.startswith('_'):
@@ -233,7 +233,7 @@ def transform_types(schema, transform):
233233

234234
def transform_fields(schema, transform):
235235
for _type in schema.type_map.values():
236-
if _type.name.startswith('_') or is_scalar_type(_type) or is_enum_type(_type):
236+
if _type.name.startswith('_') or is_scalar_type(_type) or is_enum_type(_type) or is_union_type(_type):
237237
continue
238238
field_names = list(_type.fields.keys())
239239
for field_name in field_names:
@@ -259,7 +259,7 @@ def transform_enums(schema, transform):
259259
def drop_comments(schema):
260260
for _type in schema.type_map.values():
261261
_type.description = None
262-
if _type.name.startswith('_') or is_scalar_type(_type):
262+
if _type.name.startswith('_') or is_scalar_type(_type) or is_union_type(_type):
263263
continue
264264
elif is_enum_type(_type):
265265
for e in _type.values.values():

graphql-api-generator/utils/utils.py

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def add_id_to_types(schema: GraphQLSchema):
112112
"""
113113
make = ''
114114
for _type in schema.type_map.values():
115-
if not is_db_schema_defined_type(_type):
115+
if not is_db_schema_defined_type(_type) or is_union_type(_type):
116116
continue
117117
if is_interface_type(_type):
118118
make += f'extend interface {_type.name} {{ id: ID! }} '
@@ -129,7 +129,7 @@ def add_creation_date_to_types(schema: GraphQLSchema):
129129
"""
130130
make = ''
131131
for _type in schema.type_map.values():
132-
if not is_schema_defined_type(_type):
132+
if not is_schema_defined_type(_type) or is_union_type(_type):
133133
continue
134134

135135
if is_interface_type(_type):
@@ -147,7 +147,7 @@ def add_last_update_date_to_types(schema: GraphQLSchema):
147147
"""
148148
make = ''
149149
for _type in schema.type_map.values():
150-
if not is_schema_defined_type(_type):
150+
if not is_schema_defined_type(_type) or is_union_type(_type):
151151
continue
152152
if is_interface_type(_type):
153153
make += f'extend interface {_type.name} {{ _lastUpdateDate: DateTime }} '
@@ -192,7 +192,7 @@ def add_reverse_edges(schema: GraphQLSchema):
192192
"""
193193
make = ''
194194
for _type in schema.type_map.values():
195-
if not is_db_schema_defined_type(_type):
195+
if not is_db_schema_defined_type(_type) or is_union_type(_type):
196196
continue
197197

198198
for field_name, field_type in _type.fields.items():
@@ -226,6 +226,9 @@ def add_reverse_edges(schema: GraphQLSchema):
226226
make += 'extend interface {0} {{ {1}: {2} {3} }}\n'.format(edge_from, edge_name, edge_to, directive_to_add)
227227
for implementing_type in schema.get_possible_types(edge_from):
228228
make += 'extend type {0} {{ {1}: {2} }}\n'.format(implementing_type, edge_name, edge_to)
229+
elif is_union_type(edge_from):
230+
for sub_type in edge_from.types:
231+
make += 'extend type {0} {{ {1}: {2} }}\n'.format(sub_type, edge_name, edge_to)
229232
else:
230233
make += 'extend type {0} {{ {1}: {2} {3} }}\n'.format(edge_from, edge_name, edge_to, directive_to_add)
231234
schema = add_to_schema(schema, make)
@@ -242,15 +245,15 @@ def add_input_to_create(schema: GraphQLSchema):
242245
# add create types (placeholders)
243246
make = ''
244247
for _type in schema.type_map.values():
245-
if not is_db_schema_defined_type(_type) or is_interface_type(_type):
248+
if not is_db_schema_defined_type(_type) or is_interface_type(_type) or is_union_type(_type):
246249
continue
247250
make += f'input _InputToCreate{_type.name} '
248251
schema = add_to_schema(schema, make)
249252

250253
# add fields to create types
251254
make = ''
252255
for _type in schema.type_map.values():
253-
if not is_db_schema_defined_type(_type) or is_interface_type(_type):
256+
if not is_db_schema_defined_type(_type) or is_interface_type(_type) or is_union_type(_type):
254257
continue
255258
make += f'\nextend input _InputToCreate{_type.name} {{\n'
256259
num_fields = 0
@@ -348,7 +351,6 @@ def extend_connect(schema: GraphQLSchema, _type: GraphQLType, field_type: GraphQ
348351
:param field_name:
349352
:return:
350353
"""
351-
create_name = f'_InputToCreate{field_type.name}'
352354
connect_name = f'_InputToConnect{capitalize(field_name)}Of{_type.name}'
353355
make = f'input {connect_name} {{ '
354356
make += 'connect: ID '
@@ -360,7 +362,14 @@ def extend_connect(schema: GraphQLSchema, _type: GraphQLType, field_type: GraphQ
360362
create_field = f'create{implementing_type.name}'
361363
create_implementing_type = f'_InputToCreate{implementing_type.name}'
362364
make += f'{create_field} : {create_implementing_type} '
365+
elif is_union_type(field_type):
366+
# add fields for types in the union
367+
for _sub_type in field_type.types:
368+
create_field = f'create{_sub_type.name}'
369+
create_sub_type = f'_InputToCreate{_sub_type.name}'
370+
make += f'{create_field} : {create_sub_type} '
363371
else:
372+
create_name = f'_InputToCreate{field_type.name}'
364373
make += f'create: {create_name} '
365374

366375
# Get annotations
@@ -389,7 +398,7 @@ def add_input_update(schema: GraphQLSchema):
389398
# Create update inputs
390399
make = ''
391400
for _type in schema.type_map.values():
392-
if not is_db_schema_defined_type(_type) or is_interface_type(_type):
401+
if not is_db_schema_defined_type(_type) or is_interface_type(_type) or is_union_type(_type):
393402
continue
394403
update_name = f'_InputToUpdate{_type.name}'
395404
make += f'input {update_name} '
@@ -398,24 +407,21 @@ def add_input_update(schema: GraphQLSchema):
398407
# Add fields to update type
399408
make = ''
400409
for _type in schema.type_map.values():
401-
if not is_db_schema_defined_type(_type) or is_interface_type(_type):
410+
if not is_db_schema_defined_type(_type) or is_interface_type(_type) or is_union_type(_type):
402411
continue
403412
num_fields = 0
404413
update_name = f'_InputToUpdate{_type.name}'
405414
for field_name, field in _type.fields.items():
406415
if field_name == 'id' or field_name[0] == '_':
407416
continue
408-
num_fields += 1
417+
409418
f_type = get_nullable_type(field.type)
410419
inner_field_type = get_named_type(f_type)
411420

412421
if is_enum_or_scalar(inner_field_type):
422+
num_fields += 1
413423
make += f'extend input {update_name} {{ {field_name}: {f_type} }} \n'
414-
else:
415-
# add create or connect field
416-
connect_name = f'_InputToConnect{capitalize(field_name)}Of{_type.name}'
417-
connect = copy_wrapper_structure(schema.get_type(connect_name), f_type)
418-
make += f'extend input {update_name} {{ {field_name}: {connect} }} \n'
424+
419425
if num_fields == 0:
420426
make += f'extend input {update_name} {{ _dummy: String }} \n'
421427
schema = add_to_schema(schema, make)
@@ -464,7 +470,7 @@ def add_list_of_types(schema: GraphQLSchema):
464470
"""
465471
make = ''
466472
for _type in schema.type_map.values():
467-
if not is_db_schema_defined_type(_type):
473+
if not is_db_schema_defined_type(_type) or is_union_type(_type):
468474
continue
469475

470476
make += f'type _ListOf{_type.name}s {{ ' \
@@ -484,7 +490,7 @@ def add_list_queries(schema: GraphQLSchema):
484490
"""
485491
make = ''
486492
for _type in schema.type_map.values():
487-
if not is_db_schema_defined_type(_type):
493+
if not is_db_schema_defined_type(_type) or is_list_type(_type) or is_union_type(_type):
488494
continue
489495
make += f'extend type Query {{ ' \
490496
f' listOf{_type.name}s(first:Int=10, after:ID="", filter:_FilterFor{_type.name}): _ListOf{_type.name}s ' \
@@ -594,7 +600,7 @@ def add_type_filters(schema: GraphQLSchema):
594600
"""
595601
make = ''
596602
for _type in schema.type_map.values():
597-
if not is_db_schema_defined_type(_type):
603+
if not is_db_schema_defined_type(_type) or is_union_type(_type):
598604
continue
599605

600606
make += f'input _FilterFor{_type.name} {{ ' \
@@ -630,7 +636,7 @@ def add_object_type_filters(schema: GraphQLSchema):
630636
:return:
631637
"""
632638
for _type in schema.type_map.values():
633-
if not is_db_schema_defined_type(_type):
639+
if not is_db_schema_defined_type(_type) or is_union_type(_type):
634640
continue
635641

636642
for field_name, field in _type.fields.items():
@@ -674,7 +680,7 @@ def get_field_annotations(field: GraphQLField):
674680
def add_edge_objects(schema: GraphQLSchema):
675681
make = ''
676682
for _type in schema.type_map.values():
677-
if not is_db_schema_defined_type(_type):
683+
if not is_db_schema_defined_type(_type) or is_union_type(_type):
678684
continue
679685
for field_name, field in _type.fields.items():
680686
inner_field_type = get_named_type(field.type)
@@ -704,7 +710,7 @@ def add_edge_objects(schema: GraphQLSchema):
704710
def add_fields_for_edge_types(schema: GraphQLSchema, reverse):
705711
make = ''
706712
for _type in schema.type_map.values():
707-
if not is_db_schema_defined_type(_type):
713+
if not is_db_schema_defined_type(_type) or is_union_type(_type):
708714
continue
709715
for field_name, field in _type.fields.items():
710716
inner_field_type = get_named_type(field.type)
@@ -720,7 +726,7 @@ def add_fields_for_edge_types(schema: GraphQLSchema, reverse):
720726
implementing_types = schema.get_possible_types(_type)
721727
for imp_type in implementing_types:
722728
make += f'extend type {imp_type.name} {{ _outgoing{capitalize(field_name)}EdgesFrom{_type.name}: {full_type} }}\n'
723-
729+
724730
make += f'extend {type_type_str} {_type.name} {{ _outgoing{capitalize(field_name)}EdgesFrom{_type.name}: {full_type} }}\n'
725731

726732
if reverse:
@@ -741,9 +747,13 @@ def add_fields_for_edge_types(schema: GraphQLSchema, reverse):
741747
inner_connected_types = schema.get_possible_types(inner_field_type) if is_interface_type(inner_field_type) else [inner_field_type]
742748
for inner_t in inner_connected_types:
743749
type_type_str = 'type'
744-
if is_interface_type(inner_t):
745-
type_type_str = 'interface'
746-
make += f'extend {type_type_str} {inner_t.name} {{ _incoming{edge_from}: {edge_to} }}\n'
750+
if is_union_type(inner_t):
751+
for sub_type in inner_t.types:
752+
make += f'extend type {sub_type.name} {{ _incoming{edge_from}: {edge_to} }}\n'
753+
else:
754+
if is_interface_type(inner_t):
755+
type_type_str = 'interface'
756+
make += f'extend {type_type_str} {inner_t.name} {{ _incoming{edge_from}: {edge_to} }}\n'
747757

748758
schema = add_to_schema(schema, make)
749759
return schema
@@ -793,7 +803,7 @@ def add_filters_for_edge_types(schema: GraphQLSchema):
793803
def add_input_to_create_edge_objects(schema: GraphQLSchema):
794804
make = ''
795805
for _type in schema.type_map.values():
796-
if not is_db_schema_defined_type(_type) or is_interface_type(_type):
806+
if not is_db_schema_defined_type(_type) or is_interface_type(_type) or is_union_type(_type):
797807
continue
798808
connected_types = schema.get_possible_types(_type) if is_interface_type(_type) else [_type]
799809
for field_name, field in _type.fields.items():
@@ -823,7 +833,7 @@ def add_input_to_create_edge_objects(schema: GraphQLSchema):
823833
def add_input_to_update_edge_objects(schema: GraphQLSchema):
824834
make = ''
825835
for _type in schema.type_map.values():
826-
if not is_db_schema_defined_type(_type) or is_interface_type(_type):
836+
if not is_db_schema_defined_type(_type) or is_interface_type(_type) or is_union_type(_type):
827837
continue
828838
connected_types = schema.get_possible_types(_type) if is_interface_type(_type) else [_type]
829839
for field_name, field in _type.fields.items():
@@ -845,7 +855,7 @@ def add_input_to_update_edge_objects(schema: GraphQLSchema):
845855
def add_mutation_create_edge_objects(schema: GraphQLSchema):
846856
make = ''
847857
for _type in schema.type_map.values():
848-
if not is_db_schema_defined_type(_type) or is_interface_type(_type):
858+
if not is_db_schema_defined_type(_type) or is_interface_type(_type) or is_union_type(_type):
849859
continue
850860
connected_types = schema.get_possible_types(_type) if is_interface_type(_type) else [_type]
851861
for field_name, field in _type.fields.items():
@@ -866,7 +876,7 @@ def add_mutation_update_edge_objects(schema: GraphQLSchema):
866876
make = ''
867877

868878
for _type in schema.type_map.values():
869-
if not is_db_schema_defined_type(_type) or is_interface_type(_type):
879+
if not is_db_schema_defined_type(_type) or is_interface_type(_type) or is_union_type(_type):
870880
continue
871881
connected_types = schema.get_possible_types(_type) if is_interface_type(_type) else [_type]
872882
for field_name, field in _type.fields.items():
@@ -889,7 +899,7 @@ def add_mutation_delete_edge_objects(schema: GraphQLSchema):
889899
make = ''
890900

891901
for _type in schema.type_map.values():
892-
if not is_db_schema_defined_type(_type) or is_interface_type(_type):
902+
if not is_db_schema_defined_type(_type) or is_interface_type(_type) or is_union_type(_type):
893903
continue
894904
connected_types = schema.get_possible_types(_type) if is_interface_type(_type) else [_type]
895905
for field_name, field in _type.fields.items():
@@ -909,7 +919,7 @@ def add_mutation_delete_edge_objects(schema: GraphQLSchema):
909919
def remove_field_arguments_for_types(schema: GraphQLSchema):
910920
keep_args = ['filter']
911921
for _type in schema.type_map.values():
912-
if not is_db_schema_defined_type(_type):
922+
if not is_db_schema_defined_type(_type) or is_union_type(_type):
913923
continue
914924
for field_name, field in _type.fields.items():
915925
args = {}
@@ -949,7 +959,7 @@ def add_create_mutations(schema: GraphQLSchema):
949959
"""
950960
make = ''
951961
for _type in schema.type_map.values():
952-
if not is_db_schema_defined_type(_type) or is_interface_type(_type):
962+
if not is_db_schema_defined_type(_type) or is_interface_type(_type) or is_union_type(_type):
953963
continue
954964
create = f'create{_type.name}'
955965
input_type = f'_InputToCreate{_type.name}'
@@ -967,7 +977,7 @@ def add_update_mutations(schema: GraphQLSchema):
967977
"""
968978
make = ''
969979
for _type in schema.type_map.values():
970-
if not is_db_schema_defined_type(_type) or is_interface_type(_type):
980+
if not is_db_schema_defined_type(_type) or is_interface_type(_type) or is_union_type(_type):
971981
continue
972982
update = f'update{capitalize(_type.name)} '
973983
input_type = f'_InputToUpdate{_type.name}'
@@ -985,7 +995,7 @@ def add_delete_mutations(schema: GraphQLSchema):
985995
"""
986996
make = ''
987997
for _type in schema.type_map.values():
988-
if not is_db_schema_defined_type(_type):
998+
if not is_db_schema_defined_type(_type) or is_union_type(_type):
989999
continue
9901000
delete = f'delete{_type.name}'
9911001
make += f'extend type Mutation {{ {delete}(id: ID!): {_type.name} }} '
@@ -1251,6 +1261,8 @@ def print_schema_with_directives(schema):
12511261
output += 'scalar ' + _type.name
12521262
elif is_input_type(_type):
12531263
output += 'input ' + _type.name
1264+
elif is_union_type(_type):
1265+
output += 'union ' + _type.name
12541266
else:
12551267
output += 'type ' + _type.name
12561268
if hasattr(_type, 'interfaces') and _type.interfaces:
@@ -1264,6 +1276,11 @@ def print_schema_with_directives(schema):
12641276
output += ' ' + value + '\n'
12651277
output += '}'
12661278

1279+
elif is_union_type(_type):
1280+
# For enums we can get the invloved types directly and add them
1281+
output += ' = '
1282+
output += ' | '.join([inner_type.name for inner_type in _type.types])
1283+
12671284
elif not is_enum_or_scalar(_type):
12681285
# This should be a type, or an interface
12691286
# Get directives on type

0 commit comments

Comments
 (0)