graphql_rails 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +3 -2
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +76 -73
- data/docs/README.md +1 -1
- data/docs/components/controller.md +15 -1
- data/docs/components/model.md +130 -6
- data/docs/components/routes.md +20 -10
- data/graphql_rails.gemspec +1 -1
- data/lib/generators/graphql_rails/templates/graphql_controller.erb +1 -1
- data/lib/graphql_rails/attributes/attributable.rb +6 -0
- data/lib/graphql_rails/attributes/attribute.rb +22 -9
- data/lib/graphql_rails/attributes/attribute_configurable.rb +27 -0
- data/lib/graphql_rails/attributes/attribute_name_parser.rb +4 -4
- data/lib/graphql_rails/attributes/input_attribute.rb +7 -1
- data/lib/graphql_rails/attributes/type_parseable.rb +6 -7
- data/lib/graphql_rails/controller/action.rb +4 -4
- data/lib/graphql_rails/controller/action_configuration.rb +1 -1
- data/lib/graphql_rails/controller/build_controller_action_resolver.rb +4 -15
- data/lib/graphql_rails/controller/configuration.rb +7 -2
- data/lib/graphql_rails/controller/handle_controller_error.rb +65 -0
- data/lib/graphql_rails/controller/log_controller_action.rb +1 -0
- data/lib/graphql_rails/controller/request/format_errors.rb +1 -1
- data/lib/graphql_rails/controller/request.rb +3 -2
- data/lib/graphql_rails/controller.rb +9 -6
- data/lib/graphql_rails/decorator/relation_decorator.rb +2 -2
- data/lib/graphql_rails/errors/custom_execution_error.rb +1 -1
- data/lib/graphql_rails/errors/execution_error.rb +1 -1
- data/lib/graphql_rails/model/configuration.rb +15 -2
- data/lib/graphql_rails/model/find_or_build_graphql_input_type.rb +36 -0
- data/lib/graphql_rails/model/find_or_build_graphql_type.rb +47 -13
- data/lib/graphql_rails/model/find_or_build_graphql_type_class.rb +7 -3
- data/lib/graphql_rails/model/input.rb +3 -3
- data/lib/graphql_rails/router/event_route.rb +52 -0
- data/lib/graphql_rails/router/mutation_route.rb +1 -1
- data/lib/graphql_rails/router/query_route.rb +1 -1
- data/lib/graphql_rails/router/resource_routes_builder.rb +0 -8
- data/lib/graphql_rails/router/route.rb +12 -2
- data/lib/graphql_rails/router/schema_builder.rb +15 -10
- data/lib/graphql_rails/router.rb +8 -8
- data/lib/graphql_rails/rspec_controller_helpers.rb +17 -3
- data/lib/graphql_rails/types/hidable_by_group.rb +23 -3
- data/lib/graphql_rails/types/input_object_type.rb +16 -0
- data/lib/graphql_rails/version.rb +1 -1
- metadata +10 -14
- data/lib/graphql_rails/model/build_graphql_input_type.rb +0 -43
- data/lib/graphql_rails/router/subscription_route.rb +0 -22
@@ -21,18 +21,12 @@ module GraphqlRails
|
|
21
21
|
@attributes ||= {}
|
22
22
|
end
|
23
23
|
|
24
|
-
def property(new_value = NOT_SET)
|
25
|
-
return @property if new_value == NOT_SET
|
26
|
-
|
27
|
-
@property = new_value.to_s
|
28
|
-
self
|
29
|
-
end
|
30
|
-
|
31
24
|
def field_args
|
32
25
|
[
|
33
26
|
field_name,
|
34
27
|
type_parser.type_arg,
|
35
|
-
description
|
28
|
+
description,
|
29
|
+
*field_args_options
|
36
30
|
].compact
|
37
31
|
end
|
38
32
|
|
@@ -42,7 +36,9 @@ module GraphqlRails
|
|
42
36
|
null: optional?,
|
43
37
|
camelize: camelize?,
|
44
38
|
groups: groups,
|
45
|
-
|
39
|
+
hidden_in_groups: hidden_in_groups,
|
40
|
+
**deprecation_reason_params,
|
41
|
+
**extras_options
|
46
42
|
}
|
47
43
|
end
|
48
44
|
|
@@ -52,6 +48,12 @@ module GraphqlRails
|
|
52
48
|
|
53
49
|
private
|
54
50
|
|
51
|
+
def extras_options
|
52
|
+
return {} if extras.empty?
|
53
|
+
|
54
|
+
{ extras: extras }
|
55
|
+
end
|
56
|
+
|
55
57
|
def camelize?
|
56
58
|
options[:input_format] != :original && options[:attribute_name_format] != :original
|
57
59
|
end
|
@@ -59,6 +61,17 @@ module GraphqlRails
|
|
59
61
|
def deprecation_reason_params
|
60
62
|
{ deprecation_reason: deprecation_reason }.compact
|
61
63
|
end
|
64
|
+
|
65
|
+
def field_args_options
|
66
|
+
options = { **field_args_pagination_options }
|
67
|
+
return nil if options.empty?
|
68
|
+
|
69
|
+
[options]
|
70
|
+
end
|
71
|
+
|
72
|
+
def field_args_pagination_options
|
73
|
+
pagination_options || {}
|
74
|
+
end
|
62
75
|
end
|
63
76
|
end
|
64
77
|
end
|
@@ -17,6 +17,7 @@ module GraphqlRails
|
|
17
17
|
|
18
18
|
chainable_option :description
|
19
19
|
chainable_option :options, default: {}
|
20
|
+
chainable_option :extras, default: []
|
20
21
|
chainable_option :type
|
21
22
|
end
|
22
23
|
|
@@ -32,6 +33,14 @@ module GraphqlRails
|
|
32
33
|
groups(*args)
|
33
34
|
end
|
34
35
|
|
36
|
+
def hidden_in_groups(new_groups = ChainableOptions::NOT_SET)
|
37
|
+
@hidden_in_groups ||= []
|
38
|
+
return @hidden_in_groups if new_groups == ChainableOptions::NOT_SET
|
39
|
+
|
40
|
+
@hidden_in_groups = Array(new_groups).map(&:to_s)
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
35
44
|
def required(new_value = true) # rubocop:disable Style/OptionalBooleanParameter
|
36
45
|
@required = new_value
|
37
46
|
self
|
@@ -55,6 +64,24 @@ module GraphqlRails
|
|
55
64
|
def deprecation_reason
|
56
65
|
@deprecation_reason
|
57
66
|
end
|
67
|
+
|
68
|
+
def property(new_value = ChainableOptions::NOT_SET)
|
69
|
+
return @property if new_value == ChainableOptions::NOT_SET
|
70
|
+
|
71
|
+
@property = new_value.to_s
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
def same_as(other_attribute)
|
76
|
+
other = other_attribute.dup
|
77
|
+
other.instance_variables.each do |instance_variable|
|
78
|
+
next if instance_variable == :@initial_name
|
79
|
+
|
80
|
+
instance_variable_set(instance_variable, other.instance_variable_get(instance_variable))
|
81
|
+
end
|
82
|
+
|
83
|
+
self
|
84
|
+
end
|
58
85
|
end
|
59
86
|
end
|
60
87
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module GraphqlRails
|
4
4
|
module Attributes
|
5
5
|
# Parses attribute name and can generates graphql scalar type,
|
6
|
-
#
|
6
|
+
# graphql name and etc. based on that
|
7
7
|
class AttributeNameParser
|
8
8
|
def initialize(original_name, options: {})
|
9
9
|
@original_name = original_name.to_s
|
@@ -13,9 +13,9 @@ module GraphqlRails
|
|
13
13
|
def field_name
|
14
14
|
@field_name ||= \
|
15
15
|
if original_format?
|
16
|
-
|
16
|
+
preprocessed_name
|
17
17
|
else
|
18
|
-
|
18
|
+
preprocessed_name.camelize(:lower)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -47,7 +47,7 @@ module GraphqlRails
|
|
47
47
|
options[:input_format] == :original || options[:attribute_name_format] == :original
|
48
48
|
end
|
49
49
|
|
50
|
-
def
|
50
|
+
def preprocessed_name
|
51
51
|
if name.end_with?('?')
|
52
52
|
"is_#{name.remove(/\?\Z/)}"
|
53
53
|
else
|
@@ -31,7 +31,9 @@ module GraphqlRails
|
|
31
31
|
description: description,
|
32
32
|
camelize: false,
|
33
33
|
groups: groups,
|
34
|
+
hidden_in_groups: hidden_in_groups,
|
34
35
|
**default_value_option,
|
36
|
+
**property_params,
|
35
37
|
**deprecation_reason_params
|
36
38
|
}
|
37
39
|
end
|
@@ -58,6 +60,10 @@ module GraphqlRails
|
|
58
60
|
{ deprecation_reason: deprecation_reason }.compact
|
59
61
|
end
|
60
62
|
|
63
|
+
def property_params
|
64
|
+
{ as: property }.compact
|
65
|
+
end
|
66
|
+
|
61
67
|
def attribute_naming_options
|
62
68
|
options.slice(:input_format)
|
63
69
|
end
|
@@ -79,7 +85,7 @@ module GraphqlRails
|
|
79
85
|
end
|
80
86
|
|
81
87
|
def raw_input_type
|
82
|
-
return type if type.is_a?(GraphQL::
|
88
|
+
return type if type.is_a?(GraphQL::Schema::InputObject)
|
83
89
|
return type.graphql_input_type if type.is_a?(Model::Input)
|
84
90
|
end
|
85
91
|
end
|
@@ -42,14 +42,13 @@ module GraphqlRails
|
|
42
42
|
WRAPPER_TYPES = [
|
43
43
|
GraphQL::Schema::List,
|
44
44
|
GraphQL::Schema::NonNull,
|
45
|
-
GraphQL::NonNullType,
|
46
|
-
GraphQL::ListType
|
45
|
+
GraphQL::Language::Nodes::NonNullType,
|
46
|
+
GraphQL::Language::Nodes::ListType
|
47
47
|
].freeze
|
48
48
|
|
49
49
|
GRAPHQL_BASE_TYPES = [
|
50
|
-
GraphQL::
|
51
|
-
GraphQL::
|
52
|
-
GraphQL::InputObjectType
|
50
|
+
GraphQL::Schema::Object,
|
51
|
+
GraphQL::Schema::InputObject
|
53
52
|
].freeze
|
54
53
|
|
55
54
|
RAW_GRAPHQL_TYPES = (WRAPPER_TYPES + GRAPHQL_BASE_TYPES).freeze
|
@@ -95,9 +94,9 @@ module GraphqlRails
|
|
95
94
|
end
|
96
95
|
|
97
96
|
def graphql_type_object?(type_class)
|
98
|
-
return false
|
97
|
+
return false if !type_class.is_a?(Class) && !type_class.is_a?(Module)
|
99
98
|
|
100
|
-
type_class < GraphQL::Schema::Member
|
99
|
+
type_class < GraphQL::Schema::Member::GraphQLTypeNames
|
101
100
|
end
|
102
101
|
|
103
102
|
def applicable_graphql_type?(type)
|
@@ -43,16 +43,16 @@ module GraphqlRails
|
|
43
43
|
{ null: !type_parser.required? }
|
44
44
|
end
|
45
45
|
|
46
|
+
def action_config
|
47
|
+
controller.controller_configuration.action_config(name)
|
48
|
+
end
|
49
|
+
|
46
50
|
private
|
47
51
|
|
48
52
|
attr_reader :route
|
49
53
|
|
50
54
|
delegate :type_parser, to: :action_config
|
51
55
|
|
52
|
-
def action_config
|
53
|
-
controller.controller_configuration.action_config(name)
|
54
|
-
end
|
55
|
-
|
56
56
|
def namespaced_controller_name
|
57
57
|
[route.module_name, controller_name].reject(&:empty?).join('/')
|
58
58
|
end
|
@@ -7,7 +7,7 @@ require 'graphql_rails/errors/error'
|
|
7
7
|
|
8
8
|
module GraphqlRails
|
9
9
|
class Controller
|
10
|
-
# stores all graphql_rails
|
10
|
+
# stores all graphql_rails controller specific config
|
11
11
|
class ActionConfiguration
|
12
12
|
class MissingConfigurationError < GraphqlRails::Error; end
|
13
13
|
class DeprecatedDefaultModelError < GraphqlRails::Error; end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'graphql_rails/controller/action'
|
4
3
|
require 'graphql_rails/concerns/service'
|
5
4
|
require 'graphql_rails/controller/action_configuration'
|
6
5
|
require 'graphql_rails/controller/build_controller_action_resolver/controller_action_resolver'
|
@@ -11,12 +10,12 @@ module GraphqlRails
|
|
11
10
|
class BuildControllerActionResolver
|
12
11
|
include ::GraphqlRails::Service
|
13
12
|
|
14
|
-
def initialize(
|
15
|
-
@
|
13
|
+
def initialize(action:)
|
14
|
+
@action = action
|
16
15
|
end
|
17
16
|
|
18
17
|
def call # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
19
|
-
action =
|
18
|
+
action = self.action
|
20
19
|
|
21
20
|
Class.new(ControllerActionResolver) do
|
22
21
|
graphql_name("ControllerActionResolver#{SecureRandom.hex}")
|
@@ -38,17 +37,7 @@ module GraphqlRails
|
|
38
37
|
|
39
38
|
private
|
40
39
|
|
41
|
-
attr_reader :
|
42
|
-
|
43
|
-
def build_action
|
44
|
-
Action.new(route).tap do |action|
|
45
|
-
assert_action(action)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def assert_action(action)
|
50
|
-
action.return_type
|
51
|
-
end
|
40
|
+
attr_reader :action
|
52
41
|
end
|
53
42
|
end
|
54
43
|
end
|
@@ -7,13 +7,13 @@ require 'graphql_rails/errors/error'
|
|
7
7
|
|
8
8
|
module GraphqlRails
|
9
9
|
class Controller
|
10
|
-
# stores all graphql_rails
|
10
|
+
# stores all graphql_rails controller specific config
|
11
11
|
class Configuration
|
12
12
|
class InvalidActionConfiguration < GraphqlRails::Error; end
|
13
13
|
|
14
14
|
LIB_REGEXP = %r{/graphql_rails/lib/}
|
15
15
|
|
16
|
-
attr_reader :action_by_name
|
16
|
+
attr_reader :action_by_name, :error_handlers
|
17
17
|
|
18
18
|
def initialize(controller)
|
19
19
|
@controller = controller
|
@@ -25,6 +25,7 @@ module GraphqlRails
|
|
25
25
|
|
26
26
|
@action_by_name = {}
|
27
27
|
@action_default = nil
|
28
|
+
@error_handlers = {}
|
28
29
|
end
|
29
30
|
|
30
31
|
def initialize_copy(other)
|
@@ -56,6 +57,10 @@ module GraphqlRails
|
|
56
57
|
ActionHook.new(name: hook_name, **options, &block)
|
57
58
|
end
|
58
59
|
|
60
|
+
def add_error_handler(error, with:, &block)
|
61
|
+
@error_handlers[error] = with || block
|
62
|
+
end
|
63
|
+
|
59
64
|
def action_default
|
60
65
|
@action_default ||= ActionConfiguration.new(name: :default, controller: nil)
|
61
66
|
yield(@action_default) if block_given?
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlRails
|
4
|
+
class Controller
|
5
|
+
# runs {before/around/after}_action controller hooks
|
6
|
+
class HandleControllerError
|
7
|
+
def initialize(error:, controller:)
|
8
|
+
@error = error
|
9
|
+
@controller = controller
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
return custom_handle_error if custom_handle_error?
|
14
|
+
|
15
|
+
render_unhandled_error(error)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :error, :controller
|
21
|
+
|
22
|
+
def render_unhandled_error(error)
|
23
|
+
return render(error: error) if error.is_a?(GraphQL::ExecutionError)
|
24
|
+
|
25
|
+
render(error: SystemError.new(error))
|
26
|
+
end
|
27
|
+
|
28
|
+
def custom_handle_error
|
29
|
+
return unless custom_handler
|
30
|
+
|
31
|
+
begin
|
32
|
+
if custom_handler.is_a?(Proc)
|
33
|
+
controller.instance_exec(error, &custom_handler)
|
34
|
+
else
|
35
|
+
controller.send(custom_handler)
|
36
|
+
end
|
37
|
+
rescue StandardError => e
|
38
|
+
render_unhandled_error(e)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def custom_handler
|
43
|
+
return @custom_handler if defined?(@custom_handler)
|
44
|
+
|
45
|
+
handler = controller_config.error_handlers.detect do |error_class, _handler|
|
46
|
+
error.class <= error_class
|
47
|
+
end
|
48
|
+
|
49
|
+
@custom_handler = handler&.last
|
50
|
+
end
|
51
|
+
|
52
|
+
def custom_handle_error?
|
53
|
+
custom_handler.present?
|
54
|
+
end
|
55
|
+
|
56
|
+
def controller_config
|
57
|
+
@controller_config ||= controller.class.controller_configuration
|
58
|
+
end
|
59
|
+
|
60
|
+
def render(*args, **kwargs, &block)
|
61
|
+
controller.send(:render, *args, **kwargs, &block)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -8,7 +8,7 @@ require 'graphql_rails/errors/custom_execution_error'
|
|
8
8
|
module GraphqlRails
|
9
9
|
class Controller
|
10
10
|
class Request
|
11
|
-
# Converts user provided free-form errors in to
|
11
|
+
# Converts user provided free-form errors in to meaningful graphql error classes
|
12
12
|
class FormatErrors
|
13
13
|
include Service
|
14
14
|
|
@@ -7,11 +7,12 @@ module GraphqlRails
|
|
7
7
|
require 'graphql_rails/controller/request/format_errors'
|
8
8
|
|
9
9
|
attr_accessor :object_to_return
|
10
|
-
attr_reader :errors, :context
|
10
|
+
attr_reader :errors, :context, :lookahead
|
11
11
|
|
12
12
|
def initialize(graphql_object, inputs, context)
|
13
13
|
@graphql_object = graphql_object
|
14
|
-
@inputs = inputs
|
14
|
+
@inputs = inputs.except(:lookahead)
|
15
|
+
@lookahead = inputs[:lookahead]
|
15
16
|
@context = context
|
16
17
|
end
|
17
18
|
|
@@ -6,6 +6,7 @@ require 'graphql_rails/controller/configuration'
|
|
6
6
|
require 'graphql_rails/controller/request'
|
7
7
|
require 'graphql_rails/controller/action_hooks_runner'
|
8
8
|
require 'graphql_rails/controller/log_controller_action'
|
9
|
+
require 'graphql_rails/controller/handle_controller_error'
|
9
10
|
require 'graphql_rails/errors/system_error'
|
10
11
|
|
11
12
|
module GraphqlRails
|
@@ -45,6 +46,12 @@ module GraphqlRails
|
|
45
46
|
def controller_configuration
|
46
47
|
@controller_configuration ||= Controller::Configuration.new(self)
|
47
48
|
end
|
49
|
+
|
50
|
+
def rescue_from(*errors, with: nil, &block)
|
51
|
+
Array(errors).each do |error|
|
52
|
+
controller_configuration.add_error_handler(error, with: with, &block)
|
53
|
+
end
|
54
|
+
end
|
48
55
|
end
|
49
56
|
|
50
57
|
attr_reader :action_name
|
@@ -86,12 +93,8 @@ module GraphqlRails
|
|
86
93
|
response = hooks_runner.call { public_send(action_name) }
|
87
94
|
|
88
95
|
render response if graphql_request.no_object_to_return?
|
89
|
-
rescue StandardError =>
|
90
|
-
|
91
|
-
render error: error
|
92
|
-
else
|
93
|
-
render error: SystemError.new(error)
|
94
|
-
end
|
96
|
+
rescue StandardError => e
|
97
|
+
HandleControllerError.new(error: e, controller: self).call
|
95
98
|
end
|
96
99
|
|
97
100
|
def graphql_errors_from_render_params(rendering_params)
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
module GraphqlRails
|
4
4
|
module Decorator
|
5
|
-
#
|
5
|
+
# wraps active record relation and returns decorated object instead
|
6
6
|
class RelationDecorator
|
7
7
|
delegate :map, :each, to: :to_a
|
8
|
-
delegate :limit_value, :offset_value, :count, :size, :empty?, to: :relation
|
8
|
+
delegate :limit_value, :offset_value, :count, :size, :empty?, :loaded?, to: :relation
|
9
9
|
|
10
10
|
def self.decorates?(object)
|
11
11
|
(defined?(ActiveRecord) && object.is_a?(ActiveRecord::Relation)) ||
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module GraphqlRails
|
4
|
-
# base class which is returned in case something bad happens. Contains all error rendering
|
4
|
+
# base class which is returned in case something bad happens. Contains all error rendering structure
|
5
5
|
class CustomExecutionError < ExecutionError
|
6
6
|
attr_reader :extra_graphql_data
|
7
7
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module GraphqlRails
|
4
4
|
require 'graphql'
|
5
5
|
|
6
|
-
# base class which is returned in case something bad happens. Contains all error rendering
|
6
|
+
# base class which is returned in case something bad happens. Contains all error rendering structure
|
7
7
|
class ExecutionError < GraphQL::ExecutionError
|
8
8
|
def to_h
|
9
9
|
super.merge(extra_graphql_data)
|
@@ -24,10 +24,21 @@ module GraphqlRails
|
|
24
24
|
@input = other.instance_variable_get(:@input)&.transform_values(&:dup)
|
25
25
|
end
|
26
26
|
|
27
|
+
def implements(*interfaces)
|
28
|
+
previous_implements = get_or_set_chainable_option(:implements) || []
|
29
|
+
return previous_implements if interfaces.blank?
|
30
|
+
|
31
|
+
full_implements = (previous_implements + interfaces).uniq
|
32
|
+
|
33
|
+
get_or_set_chainable_option(:implements, full_implements) || []
|
34
|
+
end
|
35
|
+
|
27
36
|
def attribute(attribute_name, **attribute_options)
|
28
37
|
key = attribute_name.to_s
|
29
38
|
|
30
|
-
attributes[key] ||= build_attribute(attribute_name)
|
39
|
+
attributes[key] ||= build_attribute(attribute_name)
|
40
|
+
|
41
|
+
attributes[key].tap do |new_attribute|
|
31
42
|
new_attribute.with(**attribute_options)
|
32
43
|
yield(new_attribute) if block_given?
|
33
44
|
end
|
@@ -52,7 +63,8 @@ module GraphqlRails
|
|
52
63
|
name: name,
|
53
64
|
description: description,
|
54
65
|
attributes: attributes,
|
55
|
-
type_name: type_name
|
66
|
+
type_name: type_name,
|
67
|
+
implements: implements
|
56
68
|
)
|
57
69
|
end
|
58
70
|
|
@@ -86,6 +98,7 @@ module GraphqlRails
|
|
86
98
|
description: description,
|
87
99
|
attributes: attributes,
|
88
100
|
type_name: type_name,
|
101
|
+
implements: implements,
|
89
102
|
force_define_attributes: true
|
90
103
|
)
|
91
104
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'graphql_rails/types/input_object_type'
|
4
|
+
require 'graphql_rails/concerns/service'
|
5
|
+
require 'graphql_rails/model/find_or_build_graphql_type'
|
6
|
+
|
7
|
+
module GraphqlRails
|
8
|
+
module Model
|
9
|
+
# stores information about model specific config, like attributes and types
|
10
|
+
class FindOrBuildGraphqlInputType < FindOrBuildGraphqlType
|
11
|
+
include ::GraphqlRails::Service
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def parent_class
|
16
|
+
GraphqlRails::Types::InputObjectType
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_attributes_batch(attributes)
|
20
|
+
klass.class_eval do
|
21
|
+
attributes.each do |attribute|
|
22
|
+
argument(*attribute.input_argument_args, **attribute.input_argument_options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_or_build_dynamic_type(attribute)
|
28
|
+
graphql_model = attribute.graphql_model
|
29
|
+
return unless graphql_model
|
30
|
+
|
31
|
+
graphql = graphql_model.graphql.input(attribute.subtype)
|
32
|
+
find_or_build_graphql_model_type(graphql)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -10,51 +10,85 @@ module GraphqlRails
|
|
10
10
|
|
11
11
|
include ::GraphqlRails::Service
|
12
12
|
|
13
|
-
|
13
|
+
# rubocop:disable Metrics/ParameterLists
|
14
|
+
def initialize(
|
15
|
+
name:,
|
16
|
+
description:,
|
17
|
+
attributes:,
|
18
|
+
type_name:,
|
19
|
+
force_define_attributes: false,
|
20
|
+
implements: []
|
21
|
+
)
|
14
22
|
@name = name
|
15
23
|
@description = description
|
16
24
|
@attributes = attributes
|
17
25
|
@type_name = type_name
|
18
26
|
@force_define_attributes = force_define_attributes
|
27
|
+
@implements = implements
|
19
28
|
end
|
29
|
+
# rubocop:enable Metrics/ParameterLists
|
20
30
|
|
21
31
|
def call
|
22
|
-
klass.tap
|
32
|
+
klass.tap do
|
33
|
+
add_attributes if new_class? || force_define_attributes
|
34
|
+
add_interfaces
|
35
|
+
end
|
23
36
|
end
|
24
37
|
|
25
38
|
private
|
26
39
|
|
27
|
-
attr_reader :name, :description, :attributes, :type_name, :force_define_attributes
|
40
|
+
attr_reader :name, :description, :attributes, :type_name, :force_define_attributes,
|
41
|
+
:implements
|
28
42
|
|
29
43
|
delegate :klass, :new_class?, to: :type_class_finder
|
30
44
|
|
45
|
+
def parent_class
|
46
|
+
GraphqlRails::Types::ObjectType
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_attributes_batch(attributes)
|
50
|
+
AddFieldsToGraphqlType.call(klass: klass, attributes: attributes)
|
51
|
+
end
|
52
|
+
|
31
53
|
def type_class_finder
|
32
54
|
@type_class_finder ||= FindOrBuildGraphqlTypeClass.new(
|
33
55
|
name: name,
|
34
56
|
type_name: type_name,
|
35
|
-
description: description
|
57
|
+
description: description,
|
58
|
+
implements: implements,
|
59
|
+
parent_class: parent_class
|
36
60
|
)
|
37
61
|
end
|
38
62
|
|
39
|
-
def
|
63
|
+
def add_attributes
|
40
64
|
scalar_attributes, dynamic_attributes = attributes.values.partition(&:scalar_type?)
|
41
65
|
|
42
|
-
|
66
|
+
add_attributes_batch(scalar_attributes)
|
43
67
|
dynamic_attributes.each { |attribute| find_or_build_dynamic_type(attribute) }
|
44
|
-
|
68
|
+
add_attributes_batch(dynamic_attributes)
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_interfaces
|
72
|
+
implements.each do |interface|
|
73
|
+
next if klass.interfaces.include?(interface)
|
74
|
+
|
75
|
+
klass.implements(interface)
|
76
|
+
end
|
45
77
|
end
|
46
78
|
|
47
79
|
def find_or_build_dynamic_type(attribute)
|
48
80
|
graphql_model = attribute.graphql_model
|
49
|
-
|
81
|
+
return unless graphql_model
|
82
|
+
|
83
|
+
find_or_build_graphql_model_type(graphql_model.graphql)
|
50
84
|
end
|
51
85
|
|
52
|
-
def find_or_build_graphql_model_type(
|
86
|
+
def find_or_build_graphql_model_type(graphql_config)
|
53
87
|
self.class.call(
|
54
|
-
name:
|
55
|
-
description:
|
56
|
-
attributes:
|
57
|
-
type_name:
|
88
|
+
name: graphql_config.name,
|
89
|
+
description: graphql_config.description,
|
90
|
+
attributes: graphql_config.attributes,
|
91
|
+
type_name: graphql_config.type_name
|
58
92
|
)
|
59
93
|
end
|
60
94
|
end
|