graphql 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graph_ql/directive.rb +9 -5
  3. data/lib/graph_ql/directives/include_directive.rb +2 -2
  4. data/lib/graph_ql/directives/skip_directive.rb +2 -2
  5. data/lib/graph_ql/enum.rb +5 -8
  6. data/lib/graph_ql/field.rb +50 -0
  7. data/lib/graph_ql/interface.rb +4 -0
  8. data/lib/graph_ql/introspection/arguments_field.rb +2 -2
  9. data/lib/graph_ql/introspection/directive_type.rb +10 -10
  10. data/lib/graph_ql/introspection/enum_value_type.rb +11 -8
  11. data/lib/graph_ql/introspection/enum_values_field.rb +5 -5
  12. data/lib/graph_ql/introspection/field_type.rb +14 -10
  13. data/lib/graph_ql/introspection/fields_field.rb +4 -4
  14. data/lib/graph_ql/introspection/input_fields_field.rb +3 -3
  15. data/lib/graph_ql/introspection/input_value_type.rb +8 -8
  16. data/lib/graph_ql/introspection/interfaces_field.rb +5 -0
  17. data/lib/graph_ql/introspection/of_type_field.rb +3 -9
  18. data/lib/graph_ql/introspection/possible_types_field.rb +3 -10
  19. data/lib/graph_ql/introspection/schema_type.rb +8 -14
  20. data/lib/graph_ql/introspection/type_kind_enum.rb +1 -1
  21. data/lib/graph_ql/introspection/type_type.rb +17 -19
  22. data/lib/graph_ql/introspection/typename_field.rb +15 -0
  23. data/lib/graph_ql/parser.rb +9 -0
  24. data/lib/graph_ql/parser/nodes.rb +17 -7
  25. data/lib/graph_ql/parser/parser.rb +7 -7
  26. data/lib/graph_ql/parser/transform.rb +23 -20
  27. data/lib/graph_ql/parser/visitor.rb +29 -13
  28. data/lib/graph_ql/query.rb +39 -16
  29. data/lib/graph_ql/query/field_resolution_strategy.rb +15 -11
  30. data/lib/graph_ql/query/type_resolver.rb +4 -2
  31. data/lib/graph_ql/repl.rb +1 -1
  32. data/lib/graph_ql/schema.rb +19 -7
  33. data/lib/graph_ql/schema/each_item_validator.rb +12 -0
  34. data/lib/graph_ql/schema/field_validator.rb +13 -0
  35. data/lib/graph_ql/schema/implementation_validator.rb +21 -0
  36. data/lib/graph_ql/schema/schema_validator.rb +10 -0
  37. data/lib/graph_ql/schema/type_reducer.rb +6 -6
  38. data/lib/graph_ql/schema/type_validator.rb +47 -0
  39. data/lib/graph_ql/static_validation.rb +18 -0
  40. data/lib/graph_ql/static_validation/argument_literals_are_compatible.rb +13 -0
  41. data/lib/graph_ql/static_validation/arguments_are_defined.rb +10 -0
  42. data/lib/graph_ql/static_validation/arguments_validator.rb +16 -0
  43. data/lib/graph_ql/static_validation/directives_are_defined.rb +18 -0
  44. data/lib/graph_ql/static_validation/fields_are_defined_on_type.rb +29 -0
  45. data/lib/graph_ql/static_validation/fields_have_appropriate_selections.rb +31 -0
  46. data/lib/graph_ql/static_validation/fields_will_merge.rb +93 -0
  47. data/lib/graph_ql/static_validation/fragment_types_exist.rb +24 -0
  48. data/lib/graph_ql/static_validation/fragments_are_used.rb +30 -0
  49. data/lib/graph_ql/static_validation/literal_validator.rb +27 -0
  50. data/lib/graph_ql/static_validation/message.rb +29 -0
  51. data/lib/graph_ql/static_validation/required_arguments_are_present.rb +13 -0
  52. data/lib/graph_ql/static_validation/type_stack.rb +87 -0
  53. data/lib/graph_ql/static_validation/validator.rb +48 -0
  54. data/lib/graph_ql/type_kinds.rb +50 -12
  55. data/lib/graph_ql/types/argument_definer.rb +7 -0
  56. data/lib/graph_ql/types/boolean_type.rb +3 -3
  57. data/lib/graph_ql/types/field_definer.rb +19 -0
  58. data/lib/graph_ql/types/float_type.rb +3 -3
  59. data/lib/graph_ql/types/input_object_type.rb +4 -0
  60. data/lib/graph_ql/types/input_value.rb +1 -1
  61. data/lib/graph_ql/types/int_type.rb +4 -4
  62. data/lib/graph_ql/types/list_type.rb +5 -1
  63. data/lib/graph_ql/types/non_null_type.rb +4 -0
  64. data/lib/graph_ql/types/object_type.rb +9 -20
  65. data/lib/graph_ql/types/scalar_type.rb +4 -0
  66. data/lib/graph_ql/types/string_type.rb +3 -3
  67. data/lib/graph_ql/types/type_definer.rb +5 -9
  68. data/lib/graph_ql/union.rb +6 -17
  69. data/lib/graph_ql/version.rb +1 -1
  70. data/lib/graphql.rb +58 -78
  71. data/readme.md +80 -7
  72. data/spec/graph_ql/interface_spec.rb +15 -1
  73. data/spec/graph_ql/introspection/directive_type_spec.rb +2 -2
  74. data/spec/graph_ql/introspection/schema_type_spec.rb +2 -1
  75. data/spec/graph_ql/introspection/type_type_spec.rb +16 -1
  76. data/spec/graph_ql/parser/parser_spec.rb +3 -1
  77. data/spec/graph_ql/parser/transform_spec.rb +12 -2
  78. data/spec/graph_ql/parser/visitor_spec.rb +13 -5
  79. data/spec/graph_ql/query_spec.rb +25 -13
  80. data/spec/graph_ql/schema/field_validator_spec.rb +21 -0
  81. data/spec/graph_ql/schema/type_reducer_spec.rb +2 -2
  82. data/spec/graph_ql/schema/type_validator_spec.rb +54 -0
  83. data/spec/graph_ql/static_validation/argument_literals_are_compatible_spec.rb +41 -0
  84. data/spec/graph_ql/static_validation/arguments_are_defined_spec.rb +40 -0
  85. data/spec/graph_ql/static_validation/directives_are_defined_spec.rb +33 -0
  86. data/spec/graph_ql/static_validation/fields_are_defined_on_type_spec.rb +59 -0
  87. data/spec/graph_ql/static_validation/fields_have_appropriate_selections_spec.rb +30 -0
  88. data/spec/graph_ql/{validations → static_validation}/fields_will_merge_spec.rb +24 -17
  89. data/spec/graph_ql/static_validation/fragment_types_exist_spec.rb +38 -0
  90. data/spec/graph_ql/static_validation/fragments_are_used_spec.rb +24 -0
  91. data/spec/graph_ql/static_validation/required_arguments_are_present_spec.rb +41 -0
  92. data/spec/graph_ql/static_validation/type_stack_spec.rb +35 -0
  93. data/spec/graph_ql/static_validation/validator_spec.rb +28 -0
  94. data/spec/graph_ql/types/object_type_spec.rb +1 -1
  95. data/spec/graph_ql/union_spec.rb +1 -14
  96. data/spec/support/dummy_app.rb +75 -53
  97. metadata +53 -31
  98. data/lib/graph_ql/fields/abstract_field.rb +0 -37
  99. data/lib/graph_ql/fields/access_field.rb +0 -24
  100. data/lib/graph_ql/fields/field.rb +0 -34
  101. data/lib/graph_ql/types/abstract_type.rb +0 -14
  102. data/lib/graph_ql/validations/fields_are_defined_on_type.rb +0 -44
  103. data/lib/graph_ql/validations/fields_will_merge.rb +0 -80
  104. data/lib/graph_ql/validations/fragments_are_used.rb +0 -24
  105. data/lib/graph_ql/validator.rb +0 -29
  106. data/spec/graph_ql/validations/fields_are_defined_on_type_spec.rb +0 -28
  107. data/spec/graph_ql/validations/fragments_are_used_spec.rb +0 -28
  108. data/spec/graph_ql/validator_spec.rb +0 -24
@@ -0,0 +1,30 @@
1
+ class GraphQL::StaticValidation::FragmentsAreUsed
2
+ include GraphQL::StaticValidation::Message::MessageHelper
3
+
4
+ def validate(context)
5
+ v = context.visitor
6
+ used_fragments = []
7
+ defined_fragments = []
8
+ v[GraphQL::Nodes::FragmentSpread] << -> (node, parent) { used_fragments << node }
9
+ v[GraphQL::Nodes::FragmentDefinition] << -> (node, parent) { defined_fragments << node}
10
+ v[GraphQL::Nodes::Document].leave << -> (node, parent) { add_errors(context.errors, used_fragments, defined_fragments) }
11
+ end
12
+
13
+ private
14
+
15
+ def add_errors(errors, used_fragments, defined_fragments)
16
+ undefined_fragments = find_difference(used_fragments, defined_fragments.map(&:name))
17
+ undefined_fragments.each do |fragment|
18
+ errors << message("Fragment #{fragment.name} was used, but not defined", fragment)
19
+ end
20
+
21
+ unused_fragments = find_difference(defined_fragments, used_fragments.map(&:name))
22
+ unused_fragments.each do |fragment|
23
+ errors << message("Fragment #{fragment.name} was defined, but not used", fragment)
24
+ end
25
+ end
26
+
27
+ def find_difference(fragments, allowed_fragment_names)
28
+ fragments.select {|f| !allowed_fragment_names.include?(f.name) }
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ # Test whether `ast_value` is a valid input for `type`
2
+ class GraphQL::StaticValidation::LiteralValidator
3
+ include GraphQL::StaticValidation::Message::MessageHelper
4
+
5
+ attr_reader :errors
6
+ def validate(ast_value, type)
7
+ if type.kind.non_null?
8
+ (!ast_value.nil?) && validate(ast_value, type.of_type)
9
+ elsif type.kind.list? && ast_value.is_a?(Array)
10
+ item_type = type.of_type
11
+ ast_value.all? { |val| validate(val, item_type) }
12
+ elsif type.kind.scalar?
13
+ !type.coerce(ast_value).nil?
14
+ elsif type.kind.enum? && ast_value.is_a?(GraphQL::Nodes::Enum)
15
+ !type.coerce(ast_value.name).nil?
16
+ elsif type.kind.input_object? && ast_value.is_a?(GraphQL::Nodes::InputObject)
17
+ fields = type.input_fields
18
+ ast_value.pairs.all? do |value|
19
+ field_type = fields[value.name].type
20
+ present_if_required = field_type.kind.non_null? ? !value.nil? : true
21
+ present_if_required && validate(value.value, field_type)
22
+ end
23
+ else
24
+ false
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,29 @@
1
+ # Generates GraphQL-compliant validation message.
2
+ # Only supports one "location", too bad :(
3
+ class GraphQL::StaticValidation::Message
4
+ # Convenience for validators
5
+ module MessageHelper
6
+ # Error `message` is located at `node`
7
+ def message(message, node)
8
+ GraphQL::StaticValidation::Message.new(message, line: node.line, col: node.col)
9
+ end
10
+ end
11
+ attr_reader :message, :line, :co
12
+ def initialize(message, line: nil, col: nil)
13
+ @message = message
14
+ @line = line
15
+ @col = col
16
+ end
17
+ def to_h
18
+ {
19
+ "message" => message,
20
+ "locations" => locations
21
+ }
22
+ end
23
+
24
+ private
25
+
26
+ def locations
27
+ @line.nil? && @col.nil ? [] : [{"line" => @line, "column" => @col}]
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ class GraphQL::StaticValidation::RequiredArgumentsArePresent < GraphQL::StaticValidation::ArgumentsValidator
2
+ def validate_node(node, defn, context)
3
+ present_argument_names = node.arguments.map(&:name)
4
+ required_argument_names = defn.arguments.values
5
+ .select { |a| a.type.kind.non_null? }
6
+ .map(&:name)
7
+
8
+ missing_names = required_argument_names - present_argument_names
9
+ if missing_names.any?
10
+ context.errors << message("#{node.class.name.split("::").last} '#{node.name}' is missing required arguments: #{missing_names.join(", ")}", node)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,87 @@
1
+ # - Ride along with `GraphQL::Visitor`
2
+ # - Track type info, expose it to validators
3
+ class GraphQL::StaticValidation::TypeStack
4
+ # These are jumping-off points for infering types down the tree
5
+ TYPE_INFERRENCE_ROOTS = [
6
+ GraphQL::Nodes::OperationDefinition,
7
+ GraphQL::Nodes::FragmentDefinition,
8
+ ]
9
+
10
+ attr_reader :schema, :object_types, :field_definitions
11
+ def initialize(schema, visitor)
12
+ @schema = schema
13
+ @object_types = []
14
+ @field_definitions = []
15
+ visitor.enter << -> (node, parent) { PUSH_STRATEGIES[node.class].push(self, node) }
16
+ visitor.leave << -> (node, parent) { PUSH_STRATEGIES[node.class].pop(self, node) }
17
+ end
18
+
19
+ private
20
+
21
+ # Look up strategies by name and use singleton instance to push and pop
22
+ PUSH_STRATEGIES = Hash.new { |hash, key| hash[key] = get_strategy_for_node_class(key) }
23
+
24
+ def self.get_strategy_for_node_class(node_class)
25
+ node_class_name = node_class.name.split("::").last
26
+ strategy_key = "#{node_class_name}Strategy"
27
+ const_defined?(strategy_key) ? const_get(strategy_key).new : NullStrategy.new
28
+ end
29
+
30
+ class FragmentWithTypeStrategy
31
+ def push(stack, node)
32
+ object_type = stack.schema.types[node.type]
33
+ if !object_type.nil?
34
+ object_type = object_type.kind.unwrap(object_type)
35
+ end
36
+ stack.object_types.push(object_type)
37
+ end
38
+
39
+ def pop(stack, node)
40
+ stack.object_types.pop
41
+ end
42
+ end
43
+
44
+ class FragmentDefinitionStrategy < FragmentWithTypeStrategy; end
45
+ class InlineFragmentStrategy < FragmentWithTypeStrategy; end
46
+
47
+ class OperationDefinitionStrategy
48
+ def push(stack, node)
49
+ # query or mutation
50
+ object_type = stack.schema.public_send(node.operation_type)
51
+ stack.object_types.push(object_type)
52
+ end
53
+ def pop(stack, node)
54
+ stack.object_types.pop
55
+ end
56
+ end
57
+
58
+ class FieldStrategy
59
+ def push(stack, node)
60
+ parent_type = stack.object_types.last
61
+ parent_type = parent_type.kind.unwrap(parent_type)
62
+ if parent_type.kind.fields?
63
+ field_class = parent_type.fields[node.name]
64
+ stack.field_definitions.push(field_class)
65
+ if !field_class.nil?
66
+ next_object_type = field_class.type
67
+ stack.object_types.push(next_object_type)
68
+ else
69
+ stack.object_types.push(nil)
70
+ end
71
+ else
72
+ stack.field_definitions.push(nil)
73
+ stack.object_types.push(parent_type)
74
+ end
75
+ end
76
+
77
+ def pop(stack, node)
78
+ stack.field_definitions.pop
79
+ stack.object_types.pop
80
+ end
81
+ end
82
+
83
+ class NullStrategy
84
+ def push(stack, node); end
85
+ def pop(stack, node); end
86
+ end
87
+ end
@@ -0,0 +1,48 @@
1
+ class GraphQL::StaticValidation::Validator
2
+ VALIDATORS = [
3
+ GraphQL::StaticValidation::DirectivesAreDefined,
4
+ GraphQL::StaticValidation::ArgumentsAreDefined,
5
+ GraphQL::StaticValidation::RequiredArgumentsArePresent,
6
+ GraphQL::StaticValidation::ArgumentLiteralsAreCompatible,
7
+ GraphQL::StaticValidation::FragmentTypesExist,
8
+ GraphQL::StaticValidation::FragmentsAreUsed,
9
+ GraphQL::StaticValidation::FieldsAreDefinedOnType,
10
+ GraphQL::StaticValidation::FieldsWillMerge,
11
+ GraphQL::StaticValidation::FieldsHaveAppropriateSelections,
12
+ ]
13
+
14
+ def initialize(schema:, validators: VALIDATORS)
15
+ @schema = schema
16
+ @validators = validators
17
+ end
18
+
19
+ def validate(document)
20
+ context = Context.new(@schema, document)
21
+ @validators.each do |validator|
22
+ validator.new.validate(context)
23
+ end
24
+ context.visitor.visit(document)
25
+ context.errors.map(&:to_h)
26
+ end
27
+
28
+ class Context
29
+ attr_reader :schema, :document, :errors, :visitor, :fragments
30
+ def initialize(schema, document)
31
+ @schema = schema
32
+ @document = document
33
+ @fragments = {}
34
+ @errors = []
35
+ @visitor = GraphQL::Visitor.new
36
+ @visitor[GraphQL::Nodes::FragmentDefinition] << -> (node, parent) { @fragments[node.name] = node }
37
+ @type_stack = GraphQL::StaticValidation::TypeStack.new(schema, visitor)
38
+ end
39
+
40
+ def object_types
41
+ @type_stack.object_types
42
+ end
43
+
44
+ def field_definition
45
+ @type_stack.field_definitions.last
46
+ end
47
+ end
48
+ end
@@ -1,15 +1,53 @@
1
1
  module GraphQL::TypeKinds
2
- KIND_NAMES = %i{
3
- SCALAR
4
- OBJECT
5
- INTERFACE
6
- UNION
7
- ENUM
8
- INPUT_OBJECT
9
- LIST
10
- NON_NULL
11
- }
12
- KIND_NAMES.each do |type_kind|
13
- const_set(type_kind, type_kind)
2
+ class TypeKind
3
+ attr_reader :name
4
+ def initialize(name, resolves: false, fields: false, wraps: false)
5
+ @name = name
6
+ @resolves = resolves
7
+ @fields = fields
8
+ @wraps = wraps
9
+ end
10
+
11
+ def resolves?; @resolves; end
12
+ def fields?; @fields; end
13
+ def wraps?; @wraps; end
14
+ def to_s; @name; end
15
+
16
+ def resolve(type, value)
17
+ if resolves?
18
+ type.resolve_type(value)
19
+ else
20
+ type
21
+ end
22
+ end
23
+
24
+ def unwrap(type)
25
+ if wraps?
26
+ wrapped_type = type.of_type
27
+ wrapped_type.kind.unwrap(wrapped_type)
28
+ else
29
+ type
30
+ end
31
+ end
32
+ end
33
+
34
+ TYPE_KINDS = [
35
+ SCALAR = TypeKind.new("SCALAR"),
36
+ OBJECT = TypeKind.new("OBJECT", fields: true),
37
+ INTERFACE = TypeKind.new("INTERFACE", resolves: true, fields: true),
38
+ UNION = TypeKind.new("UNION", resolves: true),
39
+ ENUM = TypeKind.new("ENUM"),
40
+ INPUT_OBJECT = TypeKind.new("INPUT_OBJECT"),
41
+ LIST = TypeKind.new("LIST", wraps: true),
42
+ NON_NULL = TypeKind.new("NON_NULL", wraps: true),
43
+ ]
44
+
45
+ KIND_NAMES = TYPE_KINDS.map(&:name)
46
+ class TypeKind
47
+ KIND_NAMES.each do |kind_name|
48
+ define_method("#{kind_name.downcase}?") do
49
+ self.name == kind_name
50
+ end
51
+ end
14
52
  end
15
53
  end
@@ -0,0 +1,7 @@
1
+ class GraphQL::ArgumentDefiner
2
+ include Singleton
3
+
4
+ def build(type:, desc: "", default_value: nil)
5
+ GraphQL::InputValue.new(type: type, description: desc, default_value: default_value)
6
+ end
7
+ end
@@ -1,6 +1,6 @@
1
- GraphQL::BOOLEAN_TYPE = GraphQL::ScalarType.new do
2
- name "Boolean"
3
- def coerce(value)
1
+ GraphQL::BOOLEAN_TYPE = GraphQL::ScalarType.new do |t|
2
+ t.name "Boolean"
3
+ def t.coerce(value)
4
4
  !!value
5
5
  end
6
6
  end
@@ -0,0 +1,19 @@
1
+ class GraphQL::FieldDefiner
2
+ include Singleton
3
+
4
+ def build(type:, args: {}, property: nil, desc: "", deprecation_reason: nil)
5
+ resolve = if property.nil?
6
+ -> (o, a, c) { GraphQL::Query::DEFAULT_RESOLVE }
7
+ else
8
+ -> (object, a, c) { object.send(property) }
9
+ end
10
+
11
+ GraphQL::Field.new do |f|
12
+ f.type(type)
13
+ f.arguments(args)
14
+ f.description(desc)
15
+ f.resolve(resolve)
16
+ f.deprecation_reason(deprecation_reason)
17
+ end
18
+ end
19
+ end
@@ -1,6 +1,6 @@
1
- GraphQL::FLOAT_TYPE = GraphQL::ScalarType.new do
2
- name "Float"
3
- def coerce(value)
1
+ GraphQL::FLOAT_TYPE = GraphQL::ScalarType.new do |t|
2
+ t.name "Float"
3
+ def t.coerce(value)
4
4
  value.to_f
5
5
  end
6
6
  end
@@ -14,4 +14,8 @@ class GraphQL::InputObjectType < GraphQL::ObjectType
14
14
  def kind
15
15
  GraphQL::TypeKinds::INPUT_OBJECT
16
16
  end
17
+
18
+ def to_s
19
+ "<GraphQL::InputObjectType #{name}>"
20
+ end
17
21
  end
@@ -1,7 +1,7 @@
1
1
  class GraphQL::InputValue
2
2
  attr_reader :type, :description, :default_value
3
3
  attr_accessor :name
4
- def initialize(type:, description:, default_value:, name: nil)
4
+ def initialize(type:, description: nil, default_value: nil, name: nil)
5
5
  @type = type
6
6
  @description = description,
7
7
  @default_value = default_value
@@ -1,6 +1,6 @@
1
- GraphQL::INT_TYPE = GraphQL::ScalarType.new do
2
- name "Int"
3
- def coerce(value)
4
- value.to_i
1
+ GraphQL::INT_TYPE = GraphQL::ScalarType.new do |t|
2
+ t.name "Int"
3
+ def t.coerce(value)
4
+ value.is_a?(Numeric) ? value.to_i : nil
5
5
  end
6
6
  end
@@ -1,10 +1,14 @@
1
1
  class GraphQL::ListType < GraphQL::ObjectType
2
2
  attr_reader :of_type
3
3
  def initialize(of_type:)
4
+ @name = "List"
4
5
  @of_type = of_type
5
6
  end
6
-
7
7
  def kind
8
8
  GraphQL::TypeKinds::LIST
9
9
  end
10
+
11
+ def to_s
12
+ "<GraphQL::ListType(#{of_type.name})>"
13
+ end
10
14
  end
@@ -15,4 +15,8 @@ class GraphQL::NonNullType < GraphQL::ObjectType
15
15
  def kind
16
16
  GraphQL::TypeKinds::NON_NULL
17
17
  end
18
+
19
+ def to_s
20
+ "<GraphQL::NonNullType(#{of_type.name})>"
21
+ end
18
22
  end
@@ -6,7 +6,7 @@ class GraphQL::ObjectType
6
6
  def initialize(&block)
7
7
  self.fields = []
8
8
  self.interfaces = []
9
- instance_eval(&block)
9
+ yield(self, GraphQL::TypeDefiner.instance, GraphQL::FieldDefiner.instance, GraphQL::ArgumentDefiner.instance)
10
10
  end
11
11
 
12
12
  def fields(new_fields=nil)
@@ -22,31 +22,16 @@ class GraphQL::ObjectType
22
22
  .reduce({}) { |memo, (key, value)| memo[key.to_s] = value; memo }
23
23
  # Set the name from its context on this type:
24
24
  stringified_fields.each {|k, v| v.respond_to?("name=") && v.name = k }
25
- stringified_fields["__typename"] = GraphQL::Field.new do |f|
26
- f.name "__typename"
27
- f.description "The name of this type"
28
- f.type -> { !GraphQL::STRING_TYPE }
29
- f.resolve -> (o, a, c) { self.name }
30
- end
25
+ stringified_fields["__typename"] = GraphQL::Introspection::TypenameField.create(self)
31
26
  @fields = stringified_fields
32
27
  end
33
28
 
34
- def field(type:, args: {}, property: nil, desc: "", deprecation_reason: nil)
35
- GraphQL::AccessField.new(type: type, arguments: args, property: property, description: desc, deprecation_reason: deprecation_reason)
36
- end
37
-
38
- def arg(type:, desc: "", default_value: nil)
39
- GraphQL::InputValue.new(type: type, description: desc, default_value: default_value)
40
- end
41
-
42
- def type
43
- @type ||= GraphQL::TypeDefiner.new
44
- end
45
-
46
29
  def interfaces(new_interfaces=nil)
47
30
  if new_interfaces.nil?
48
31
  @interfaces
49
32
  else
33
+ # if you define interfaces twice, you're gonna have a bad time :(
34
+ # (because it gets registered with that interface, then overriden)
50
35
  @interfaces = new_interfaces
51
36
  new_interfaces.each {|i| i.possible_types << self }
52
37
  end
@@ -57,6 +42,10 @@ class GraphQL::ObjectType
57
42
  end
58
43
 
59
44
  def to_s
60
- name
45
+ "<GraphQL::ObjectType #{name}>"
46
+ end
47
+
48
+ def inspect
49
+ to_s
61
50
  end
62
51
  end