File: has_single_input_argument.rb

package info (click to toggle)
ruby-graphql 2.2.17-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,584 kB
  • sloc: ruby: 67,505; ansic: 1,753; yacc: 831; javascript: 331; makefile: 6
file content (156 lines) | stat: -rw-r--r-- 5,117 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# frozen_string_literal: true

module GraphQL
  class Schema
    module HasSingleInputArgument
      def resolve_with_support(**inputs)
        if inputs[:input].is_a?(InputObject)
          input = inputs[:input].to_kwargs
        else
          input = inputs[:input]
        end

        new_extras = field ? field.extras : []
        all_extras = self.class.extras + new_extras

        # Transfer these from the top-level hash to the
        # shortcutted `input:` object
        all_extras.each do |ext|
          # It's possible that the `extra` was not passed along by this point,
          # don't re-add it if it wasn't given here.
          if inputs.key?(ext)
            input[ext] = inputs[ext]
          end
        end

        if input
          # This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
          input_kwargs = input.to_h
        else
          # Relay Classic Mutations with no `argument`s
          # don't require `input:`
          input_kwargs = {}
        end

        if input_kwargs.any?
          super(**input_kwargs)
        else
          super()
        end
      end

      def self.included(base)
        base.extend(ClassMethods)
      end

      module ClassMethods
        def dummy
          @dummy ||= begin
            d = Class.new(GraphQL::Schema::Resolver)
            d.argument_class(self.argument_class)
            # TODO make this lazier?
            d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
            d
          end
        end

        def field_arguments(context = GraphQL::Query::NullContext.instance)
          dummy.arguments(context)
        end

        def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
          dummy.get_argument(name, context)
        end

        def own_field_arguments
          dummy.own_arguments
        end

        def any_field_arguments?
          dummy.any_arguments?
        end

        def all_field_argument_definitions
          dummy.all_argument_definitions
        end

        # Also apply this argument to the input type:
        def argument(*args, own_argument: false, **kwargs, &block)
          it = input_type # make sure any inherited arguments are already added to it
          arg = super(*args, **kwargs, &block)

          # This definition might be overriding something inherited;
          # if it is, remove the inherited definition so it's not confused at runtime as having multiple definitions
          prev_args = it.own_arguments[arg.graphql_name]
          case prev_args
          when GraphQL::Schema::Argument
            if prev_args.owner != self
              it.own_arguments.delete(arg.graphql_name)
            end
          when Array
            prev_args.reject! { |a| a.owner != self }
            if prev_args.empty?
              it.own_arguments.delete(arg.graphql_name)
            end
          end

          it.add_argument(arg)
          arg
        end

        # The base class for generated input object types
        # @param new_class [Class] The base class to use for generating input object definitions
        # @return [Class] The base class for this mutation's generated input object (default is {GraphQL::Schema::InputObject})
        def input_object_class(new_class = nil)
          if new_class
            @input_object_class = new_class
          end
          @input_object_class || (superclass.respond_to?(:input_object_class) ? superclass.input_object_class : GraphQL::Schema::InputObject)
        end

        # @param new_input_type [Class, nil] If provided, it configures this mutation to accept `new_input_type` instead of generating an input type
        # @return [Class] The generated {Schema::InputObject} class for this mutation's `input`
        def input_type(new_input_type = nil)
          if new_input_type
            @input_type = new_input_type
          end
          @input_type ||= generate_input_type
        end

        private

        # Generate the input type for the `input:` argument
        # To customize how input objects are generated, override this method
        # @return [Class] a subclass of {.input_object_class}
        def generate_input_type
          mutation_args = all_argument_definitions
          mutation_class = self
          Class.new(input_object_class) do
            class << self
              def default_graphql_name
                "#{self.mutation.graphql_name}Input"
              end

              def description(new_desc = nil)
                super || "Autogenerated input type of #{self.mutation.graphql_name}"
              end
            end
            mutation(mutation_class)
            # these might be inherited:
            mutation_args.each do |arg|
              add_argument(arg)
            end
          end
        end
      end

      private

      def authorize_arguments(args, values)
        # remove the `input` wrapper to match values
        input_args = args["input"].type.unwrap.arguments(context)
        super(input_args, values)
      end
    end
  end
end