|
1 |
| -from .language.ast import ListType, NonNullType, NamedType |
2 |
| -from .type.definition import GraphQLList, GraphQLNonNull |
| 1 | +from .language import ast |
| 2 | +from .type.definition import ( |
| 3 | + GraphQLInputObjectType, |
| 4 | + GraphQLObjectType, |
| 5 | + GraphQLInterfaceType, |
| 6 | + GraphQLUnionType, |
| 7 | + GraphQLList, |
| 8 | + GraphQLNonNull, |
| 9 | + get_named_type, |
| 10 | + get_nullable_type, |
| 11 | + is_composite_type, |
| 12 | +) |
| 13 | +from .type.introspection import SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef |
3 | 14 |
|
4 | 15 |
|
5 | 16 | def type_from_ast(schema, input_type_ast):
|
6 |
| - if isinstance(input_type_ast, ListType): |
| 17 | + if isinstance(input_type_ast, ast.ListType): |
7 | 18 | inner_type = type_from_ast(schema, input_type_ast.type)
|
8 | 19 | if inner_type:
|
9 | 20 | return GraphQLList(inner_type)
|
10 | 21 | else:
|
11 | 22 | return None
|
12 |
| - if isinstance(input_type_ast, NonNullType): |
| 23 | + if isinstance(input_type_ast, ast.NonNullType): |
13 | 24 | inner_type = type_from_ast(schema, input_type_ast.type)
|
14 | 25 | if inner_type:
|
15 | 26 | return GraphQLNonNull(inner_type)
|
16 | 27 | else:
|
17 | 28 | return None
|
18 |
| - assert isinstance(input_type_ast, NamedType), 'Must be a type name.' |
| 29 | + assert isinstance(input_type_ast, ast.NamedType), 'Must be a type name.' |
19 | 30 | return schema.get_type(input_type_ast.name.value)
|
20 | 31 |
|
21 | 32 |
|
22 | 33 | def is_nullish(value):
|
23 | 34 | return value is None or value != value
|
| 35 | + |
| 36 | + |
| 37 | +def pop(lst): |
| 38 | + if lst: |
| 39 | + lst.pop() |
| 40 | + |
| 41 | + |
| 42 | +class TypeInfo(object): |
| 43 | + def __init__(self, schema): |
| 44 | + self._schema = schema |
| 45 | + self._type_stack = [] |
| 46 | + self._parent_type_stack = [] |
| 47 | + self._input_type_stack = [] |
| 48 | + self._field_def_stack = [] |
| 49 | + self._directive = None |
| 50 | + self._argument = None |
| 51 | + |
| 52 | + def get_type(self): |
| 53 | + if self._type_stack: |
| 54 | + return self._type_stack[-1] |
| 55 | + |
| 56 | + def get_parent_type(self): |
| 57 | + if self._parent_type_stack: |
| 58 | + return self._parent_type_stack[-1] |
| 59 | + |
| 60 | + def get_input_type(self): |
| 61 | + if self._input_type_stack: |
| 62 | + return self._input_type_stack[-1] |
| 63 | + |
| 64 | + def get_field_def(self): |
| 65 | + if self._field_def_stack: |
| 66 | + return self._field_def_stack[-1] |
| 67 | + |
| 68 | + def get_directive(self): |
| 69 | + return self._directive |
| 70 | + |
| 71 | + def get_argument(self): |
| 72 | + return self._argument |
| 73 | + |
| 74 | + def enter(self, node): |
| 75 | + schema = self._schema |
| 76 | + type = None |
| 77 | + if isinstance(node, ast.SelectionSet): |
| 78 | + named_type = get_named_type(self.get_type()) |
| 79 | + composite_type = None |
| 80 | + if is_composite_type(named_type): |
| 81 | + composite_type = named_type |
| 82 | + self._parent_type_stack.append(composite_type) |
| 83 | + elif isinstance(node, ast.Field): |
| 84 | + parent_type = self.get_parent_type() |
| 85 | + field_def = None |
| 86 | + if parent_type: |
| 87 | + field_def = get_field_def(schema, parent_type, node) |
| 88 | + self._field_def_stack.append(field_def) |
| 89 | + self._type_stack.append(field_def and field_def.type) |
| 90 | + elif isinstance(node, ast.Directive): |
| 91 | + self._directive = schema.get_directive(node.name.value) |
| 92 | + elif isinstance(node, ast.OperationDefinition): |
| 93 | + if node.operation == 'query': |
| 94 | + type = schema.get_query_type() |
| 95 | + elif node.operation == 'mutation': |
| 96 | + type = schema.get_mutation_type() |
| 97 | + self._type_stack.append(type) |
| 98 | + elif isinstance(node, (ast.InlineFragment, ast.FragmentDefinition)): |
| 99 | + type = type_from_ast(schema, node.type_condition) |
| 100 | + self._type_stack.append(type) |
| 101 | + elif isinstance(node, ast.VariableDefinition): |
| 102 | + self._input_type_stack.append(type_from_ast(schema, node.type)) |
| 103 | + elif isinstance(node, ast.Argument): |
| 104 | + arg_def = None |
| 105 | + arg_type = None |
| 106 | + field_or_directive = self.get_directive() or self.get_field_def() |
| 107 | + if field_or_directive: |
| 108 | + arg_def = filter(lambda arg: arg.name == node.name.value, field_or_directive.args) |
| 109 | + if arg_def: |
| 110 | + arg_def = arg_def[0] |
| 111 | + arg_type = arg_def.type |
| 112 | + else: |
| 113 | + arg_def = None |
| 114 | + self._argument = arg_def |
| 115 | + self._input_type_stack.append(arg_type) |
| 116 | + elif isinstance(node, ast.ListType): |
| 117 | + list_type = get_nullable_type(self.get_input_type()) |
| 118 | + self._input_type_stack.append( |
| 119 | + list_type.of_type if isinstance(list_type, GraphQLList) else None |
| 120 | + ) |
| 121 | + elif isinstance(node, ast.ObjectField): |
| 122 | + object_type = get_named_type(self.get_input_type()) |
| 123 | + field_type = None |
| 124 | + if isinstance(object_type, GraphQLInputObjectType): |
| 125 | + input_field = object_type.get_fields().get(node.name.value) |
| 126 | + field_type = input_field.type if input_field else None |
| 127 | + self._input_type_stack.append(field_type) |
| 128 | + |
| 129 | + def leave(self, node): |
| 130 | + if isinstance(node, ast.SelectionSet): |
| 131 | + pop(self._parent_type_stack) |
| 132 | + elif isinstance(node, ast.Field): |
| 133 | + pop(self._field_def_stack) |
| 134 | + pop(self._type_stack) |
| 135 | + elif isinstance(node, ast.Directive): |
| 136 | + self._directive = None |
| 137 | + elif isinstance(node, ( |
| 138 | + ast.OperationDefinition, |
| 139 | + ast.InlineFragment, |
| 140 | + ast.FragmentDefinition, |
| 141 | + )): |
| 142 | + pop(self._type_stack) |
| 143 | + elif isinstance(node, ast.VariableDefinition): |
| 144 | + pop(self._input_type_stack) |
| 145 | + elif isinstance(node, ast.Argument): |
| 146 | + self._argument = None |
| 147 | + pop(self._input_type_stack) |
| 148 | + elif isinstance(node, (ast.ListType, ast.ObjectField)): |
| 149 | + pop(self._input_type_stack) |
| 150 | + |
| 151 | + |
| 152 | +def get_field_def(schema, parent_type, field_ast): |
| 153 | + """Not exactly the same as the executor's definition of get_field_def, in this |
| 154 | + statically evaluated environment we do not always have an Object type, |
| 155 | + and need to handle Interface and Union types.""" |
| 156 | + name = field_ast.name.value |
| 157 | + if name == SchemaMetaFieldDef.name and schema.get_query_type() == parent_type: |
| 158 | + return SchemaMetaFieldDef |
| 159 | + elif name == TypeMetaFieldDef.name and schema.get_query_type() == parent_type: |
| 160 | + return TypeMetaFieldDef |
| 161 | + elif name == TypeNameMetaFieldDef.name and \ |
| 162 | + isinstance(parent_type, ( |
| 163 | + GraphQLObjectType, |
| 164 | + GraphQLInterfaceType, |
| 165 | + GraphQLUnionType, |
| 166 | + )): |
| 167 | + return TypeNameMetaFieldDef |
| 168 | + elif isinstance(parent_type, (GraphQLObjectType, GraphQLInterfaceType)): |
| 169 | + return parent_type.get_fields().get(name) |
0 commit comments