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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +3 -2
  3. data/CHANGELOG.md +21 -0
  4. data/Gemfile.lock +76 -73
  5. data/docs/README.md +1 -1
  6. data/docs/components/controller.md +15 -1
  7. data/docs/components/model.md +130 -6
  8. data/docs/components/routes.md +20 -10
  9. data/graphql_rails.gemspec +1 -1
  10. data/lib/generators/graphql_rails/templates/graphql_controller.erb +1 -1
  11. data/lib/graphql_rails/attributes/attributable.rb +6 -0
  12. data/lib/graphql_rails/attributes/attribute.rb +22 -9
  13. data/lib/graphql_rails/attributes/attribute_configurable.rb +27 -0
  14. data/lib/graphql_rails/attributes/attribute_name_parser.rb +4 -4
  15. data/lib/graphql_rails/attributes/input_attribute.rb +7 -1
  16. data/lib/graphql_rails/attributes/type_parseable.rb +6 -7
  17. data/lib/graphql_rails/controller/action.rb +4 -4
  18. data/lib/graphql_rails/controller/action_configuration.rb +1 -1
  19. data/lib/graphql_rails/controller/build_controller_action_resolver.rb +4 -15
  20. data/lib/graphql_rails/controller/configuration.rb +7 -2
  21. data/lib/graphql_rails/controller/handle_controller_error.rb +65 -0
  22. data/lib/graphql_rails/controller/log_controller_action.rb +1 -0
  23. data/lib/graphql_rails/controller/request/format_errors.rb +1 -1
  24. data/lib/graphql_rails/controller/request.rb +3 -2
  25. data/lib/graphql_rails/controller.rb +9 -6
  26. data/lib/graphql_rails/decorator/relation_decorator.rb +2 -2
  27. data/lib/graphql_rails/errors/custom_execution_error.rb +1 -1
  28. data/lib/graphql_rails/errors/execution_error.rb +1 -1
  29. data/lib/graphql_rails/model/configuration.rb +15 -2
  30. data/lib/graphql_rails/model/find_or_build_graphql_input_type.rb +36 -0
  31. data/lib/graphql_rails/model/find_or_build_graphql_type.rb +47 -13
  32. data/lib/graphql_rails/model/find_or_build_graphql_type_class.rb +7 -3
  33. data/lib/graphql_rails/model/input.rb +3 -3
  34. data/lib/graphql_rails/router/event_route.rb +52 -0
  35. data/lib/graphql_rails/router/mutation_route.rb +1 -1
  36. data/lib/graphql_rails/router/query_route.rb +1 -1
  37. data/lib/graphql_rails/router/resource_routes_builder.rb +0 -8
  38. data/lib/graphql_rails/router/route.rb +12 -2
  39. data/lib/graphql_rails/router/schema_builder.rb +15 -10
  40. data/lib/graphql_rails/router.rb +8 -8
  41. data/lib/graphql_rails/rspec_controller_helpers.rb +17 -3
  42. data/lib/graphql_rails/types/hidable_by_group.rb +23 -3
  43. data/lib/graphql_rails/types/input_object_type.rb +16 -0
  44. data/lib/graphql_rails/version.rb +1 -1
  45. metadata +10 -14
  46. data/lib/graphql_rails/model/build_graphql_input_type.rb +0 -43
  47. data/lib/graphql_rails/router/subscription_route.rb +0 -22
@@ -9,11 +9,13 @@ module GraphqlRails
9
9
 
10
10
  include ::GraphqlRails::Service
11
11
 
12
- def initialize(name:, type_name:, description: nil)
12
+ def initialize(name:, type_name:, parent_class:, description: nil, implements: [])
13
13
  @name = name
14
14
  @type_name = type_name
15
15
  @description = description
16
16
  @new_class = false
17
+ @parent_class = parent_class
18
+ @implements = implements
17
19
  end
18
20
 
19
21
  def klass
@@ -27,15 +29,17 @@ module GraphqlRails
27
29
  private
28
30
 
29
31
  attr_accessor :new_class
30
- attr_reader :name, :type_name, :description
32
+ attr_reader :name, :type_name, :description, :parent_class, :implements
31
33
 
32
34
  def build_graphql_type_klass
33
35
  graphql_type_name = name
34
36
  graphql_type_description = description
37
+ interfaces = implements
35
38
 
36
- graphql_type_klass = Class.new(GraphqlRails::Types::ObjectType) do
39
+ graphql_type_klass = Class.new(parent_class) do
37
40
  graphql_name(graphql_type_name)
38
41
  description(graphql_type_description)
42
+ interfaces.each { |interface| implements(interface) }
39
43
  end
40
44
 
41
45
  self.new_class = true
@@ -6,7 +6,7 @@ module GraphqlRails
6
6
  class Input
7
7
  require 'graphql_rails/concerns/chainable_options'
8
8
  require 'graphql_rails/model/configurable'
9
- require 'graphql_rails/model/build_graphql_input_type'
9
+ require 'graphql_rails/model/find_or_build_graphql_input_type'
10
10
 
11
11
  include Configurable
12
12
 
@@ -18,8 +18,8 @@ module GraphqlRails
18
18
  end
19
19
 
20
20
  def graphql_input_type
21
- @graphql_input_type ||= BuildGraphqlInputType.call(
22
- name: name, description: description, attributes: attributes
21
+ @graphql_input_type ||= FindOrBuildGraphqlInputType.call(
22
+ name: name, description: description, attributes: attributes, type_name: type_name
23
23
  )
24
24
  end
25
25
 
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'route'
4
+
5
+ module GraphqlRails
6
+ class Router
7
+ # stores subscription type graphql action info
8
+ class EventRoute
9
+ attr_reader :name, :module_name, :subscription_class, :groups, :scope_names
10
+
11
+ def initialize(name, subscription_class: nil, groups: nil, scope_names: [], **options)
12
+ @name = name.to_s.camelize(:lower)
13
+ @module_name = options[:module].to_s
14
+ @groups = groups
15
+ @subscription_class = subscription_class
16
+ @scope_names = scope_names
17
+ end
18
+
19
+ def show_in_group?(group_name)
20
+ return true if groups.nil? || groups.empty?
21
+
22
+ groups.include?(group_name&.to_sym)
23
+ end
24
+
25
+ def field_options
26
+ { subscription: subscription }
27
+ end
28
+
29
+ def subscription
30
+ if subscription_class.present?
31
+ subscription_class.is_a?(String) ? Object.const_get(subscription_class) : subscription_class
32
+ else
33
+ klass_name = ['subscriptions/', name.underscore, 'subscription'].join('_').camelize
34
+
35
+ Object.const_get(klass_name)
36
+ end
37
+ end
38
+
39
+ def mutation?
40
+ false
41
+ end
42
+
43
+ def query?
44
+ false
45
+ end
46
+
47
+ def event?
48
+ true
49
+ end
50
+ end
51
+ end
52
+ end
@@ -14,7 +14,7 @@ module GraphqlRails
14
14
  true
15
15
  end
16
16
 
17
- def subscription?
17
+ def event?
18
18
  false
19
19
  end
20
20
  end
@@ -14,7 +14,7 @@ module GraphqlRails
14
14
  false
15
15
  end
16
16
 
17
- def subscription?
17
+ def event?
18
18
  false
19
19
  end
20
20
  end
@@ -28,10 +28,6 @@ module GraphqlRails
28
28
  routes << build_mutation(*args, **kwargs)
29
29
  end
30
30
 
31
- def subscription(*args, **kwargs)
32
- routes << build_subscription(*args, **kwargs)
33
- end
34
-
35
31
  private
36
32
 
37
33
  attr_reader :autogenerated_action_names, :name, :options
@@ -66,10 +62,6 @@ module GraphqlRails
66
62
  build_route(QueryRoute, *args, **kwargs)
67
63
  end
68
64
 
69
- def build_subscription(*args, **kwargs)
70
- build_route(SubscriptionRoute, *args, **kwargs)
71
- end
72
-
73
65
  # rubocop:disable Metrics/ParameterLists
74
66
  def build_route(builder, action, prefix: action, suffix: false, on: :member, **custom_options)
75
67
  if suffix == true
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../controller/build_controller_action_resolver'
4
+ require 'graphql_rails/controller/action'
4
5
 
5
6
  module GraphqlRails
6
7
  class Router
@@ -38,7 +39,7 @@ module GraphqlRails
38
39
  if function
39
40
  { function: function }
40
41
  else
41
- { resolver: resolver }
42
+ { resolver: resolver, extras: [:lookahead], **resolver_options }
42
43
  end
43
44
  end
44
45
 
@@ -47,7 +48,16 @@ module GraphqlRails
47
48
  attr_reader :function
48
49
 
49
50
  def resolver
50
- @resolver ||= Controller::BuildControllerActionResolver.call(route: self)
51
+ @resolver ||= Controller::BuildControllerActionResolver.call(action: action)
52
+ end
53
+
54
+ def action
55
+ @action ||= Controller::Action.new(self).tap(&:return_type)
56
+ end
57
+
58
+ def resolver_options
59
+ action_config = action.action_config
60
+ action_config.pagination_options || {}
51
61
  end
52
62
  end
53
63
  end
@@ -7,12 +7,12 @@ module GraphqlRails
7
7
  require_relative './plain_cursor_encoder'
8
8
  require_relative './build_schema_action_type'
9
9
 
10
- attr_reader :queries, :mutations, :subscriptions, :raw_actions
10
+ attr_reader :queries, :mutations, :events, :raw_actions
11
11
 
12
- def initialize(queries:, mutations:, subscriptions:, raw_actions:, group: nil)
12
+ def initialize(queries:, mutations:, events:, raw_actions:, group: nil)
13
13
  @queries = queries
14
14
  @mutations = mutations
15
- @subscriptions = subscriptions
15
+ @events = events
16
16
  @raw_actions = raw_actions
17
17
  @group = group
18
18
  end
@@ -20,26 +20,31 @@ module GraphqlRails
20
20
  def call
21
21
  query_type = build_group_type('Query', queries)
22
22
  mutation_type = build_group_type('Mutation', mutations)
23
- subscription_type = build_group_type('Subscription', subscriptions)
24
- raw = raw_actions
23
+ subscription_type = build_group_type('Subscription', events)
25
24
 
25
+ define_schema_class(query_type, mutation_type, subscription_type, raw_actions)
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :group
31
+
32
+ # rubocop:disable Metrics/MethodLength
33
+ def define_schema_class(query_type, mutation_type, subscription_type, raw)
26
34
  Class.new(GraphQL::Schema) do
27
35
  connections.add(
28
36
  GraphqlRails::Decorator::RelationDecorator,
29
37
  GraphQL::Pagination::ActiveRecordRelationConnection
30
38
  )
31
39
  cursor_encoder(Router::PlainCursorEncoder)
32
- raw.each { |action| send(action[:name], *action[:args], &action[:block]) }
40
+ raw.each { |action| send(action[:name], *action[:args], **action[:kwargs], &action[:block]) }
33
41
 
34
42
  query(query_type) if query_type
35
43
  mutation(mutation_type) if mutation_type
36
44
  subscription(subscription_type) if subscription_type
37
45
  end
38
46
  end
39
-
40
- private
41
-
42
- attr_reader :group
47
+ # rubocop:enable Metrics/MethodLength
43
48
 
44
49
  def build_group_type(type_name, routes)
45
50
  group_name = group
@@ -5,7 +5,7 @@ require 'active_support/core_ext/string/inflections'
5
5
  require 'graphql_rails/router/schema_builder'
6
6
  require 'graphql_rails/router/mutation_route'
7
7
  require 'graphql_rails/router/query_route'
8
- require 'graphql_rails/router/subscription_route'
8
+ require 'graphql_rails/router/event_route'
9
9
  require 'graphql_rails/router/resource_routes_builder'
10
10
 
11
11
  module GraphqlRails
@@ -63,13 +63,13 @@ module GraphqlRails
63
63
  routes << build_route(MutationRoute, name, **options)
64
64
  end
65
65
 
66
- def subscription(name, **options)
67
- routes << build_route(SubscriptionRoute, name, **options)
66
+ def event(name, **options)
67
+ routes << build_route(EventRoute, name, **options)
68
68
  end
69
69
 
70
70
  RAW_ACTION_NAMES.each do |action_name|
71
- define_method(action_name) do |*args, &block|
72
- add_raw_action(action_name, *args, &block)
71
+ define_method(action_name) do |*args, **kwargs, &block|
72
+ add_raw_action(action_name, *args, **kwargs, &block)
73
73
  end
74
74
  end
75
75
 
@@ -77,7 +77,7 @@ module GraphqlRails
77
77
  @graphql_schema[group&.to_sym] ||= SchemaBuilder.new(
78
78
  queries: routes.select(&:query?),
79
79
  mutations: routes.select(&:mutation?),
80
- subscriptions: routes.select(&:subscription?),
80
+ events: routes.select(&:event?),
81
81
  raw_actions: raw_graphql_actions,
82
82
  group: group
83
83
  ).call
@@ -110,8 +110,8 @@ module GraphqlRails
110
110
  { module_name: module_name, group_names: group_names, scope_names: scope_names }
111
111
  end
112
112
 
113
- def add_raw_action(name, *args, &block)
114
- raw_graphql_actions << { name: name, args: args, block: block }
113
+ def add_raw_action(name, *args, **kwargs, &block)
114
+ raw_graphql_actions << { name: name, args: args, kwargs: kwargs, block: block }
115
115
  end
116
116
 
117
117
  def build_route(route_builder, name, **options)
@@ -46,6 +46,14 @@ module GraphqlRails
46
46
  !success?
47
47
  end
48
48
 
49
+ def controller
50
+ request.controller
51
+ end
52
+
53
+ def action_name
54
+ request.action_name
55
+ end
56
+
49
57
  private
50
58
 
51
59
  attr_reader :request
@@ -94,15 +102,21 @@ module GraphqlRails
94
102
 
95
103
  # controller request object more suitable for testing
96
104
  class Request < GraphqlRails::Controller::Request
97
- def initialize(params, context)
98
- super(nil, params, context)
105
+ attr_reader :controller, :action_name
106
+
107
+ def initialize(params, context, controller: nil, action_name: nil)
108
+ inputs = params || {}
109
+ inputs = inputs.merge(lookahead: ::GraphQL::Execution::Lookahead::NullLookahead.new)
110
+ @controller = controller
111
+ @action_name = action_name
112
+ super(nil, inputs, context)
99
113
  end
100
114
  end
101
115
 
102
116
  def query(query_name, params: {}, context: {})
103
117
  schema_builder = SingleControllerSchemaBuilder.new(described_class)
104
118
  context_object = FakeContext.new(values: context, schema: schema_builder.call)
105
- request = Request.new(params, context_object)
119
+ request = Request.new(params, context_object, controller: described_class, action_name: query_name)
106
120
  described_class.new(request).call(query_name)
107
121
 
108
122
  @response = Response.new(request)
@@ -6,10 +6,11 @@ module GraphqlRails
6
6
  module Types
7
7
  # Add visibility option based on groups
8
8
  module HidableByGroup
9
- def initialize(*args, groups: [], **kwargs, &block)
9
+ def initialize(*args, groups: [], hidden_in_groups: [], **kwargs, &block)
10
10
  super(*args, **kwargs, &block)
11
11
 
12
- @groups = groups.map(&:to_s)
12
+ @hidden_in_groups = hidden_in_groups.map(&:to_s)
13
+ @groups = groups.map(&:to_s) - @hidden_in_groups
13
14
  end
14
15
 
15
16
  def visible?(context)
@@ -22,10 +23,29 @@ module GraphqlRails
22
23
  @groups
23
24
  end
24
25
 
26
+ def hidden_in_groups
27
+ @hidden_in_groups
28
+ end
29
+
25
30
  def visible_in_context_group?(context)
31
+ group = context_graphql_group(context)
32
+
33
+ return true if no_visibility_configuration?(group)
34
+ return groups.include?(group) unless groups.empty?
35
+
36
+ !hidden_in_groups.include?(group)
37
+ end
38
+
39
+ def no_visibility_configuration?(group)
40
+ return true if group.nil?
41
+
42
+ groups.empty? && hidden_in_groups.empty?
43
+ end
44
+
45
+ def context_graphql_group(context)
26
46
  group = context[:graphql_group] || context['graphql_group']
27
47
 
28
- group.nil? || groups.empty? || groups.include?(group.to_s)
48
+ group.nil? ? nil : group.to_s
29
49
  end
30
50
  end
31
51
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphql_rails/types/argument_type'
4
+
5
+ module GraphqlRails
6
+ module Types
7
+ # Base graphql type class for all GraphqlRails models
8
+ class InputObjectType < GraphQL::Schema::InputObject
9
+ argument_class(GraphqlRails::Types::ArgumentType)
10
+
11
+ def self.inspect
12
+ "#{GraphQL::Schema::InputObject}(#{graphql_name})"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GraphqlRails
4
- VERSION = '2.3.0'
4
+ VERSION = '3.0.0'
5
5
  end
metadata CHANGED
@@ -1,35 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Povilas Jurčys
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-25 00:00:00.000000000 Z
11
+ date: 2024-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.12'
20
- - - ">="
17
+ - - '='
21
18
  - !ruby/object:Gem::Version
22
- version: 1.12.4
19
+ version: 2.1.7
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - "~>"
28
- - !ruby/object:Gem::Version
29
- version: '1.12'
30
- - - ">="
24
+ - - '='
31
25
  - !ruby/object:Gem::Version
32
- version: 1.12.4
26
+ version: 2.1.7
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: activesupport
35
29
  requirement: !ruby/object:Gem::Requirement
@@ -190,6 +184,7 @@ files:
190
184
  - lib/graphql_rails/controller/build_controller_action_resolver.rb
191
185
  - lib/graphql_rails/controller/build_controller_action_resolver/controller_action_resolver.rb
192
186
  - lib/graphql_rails/controller/configuration.rb
187
+ - lib/graphql_rails/controller/handle_controller_error.rb
193
188
  - lib/graphql_rails/controller/log_controller_action.rb
194
189
  - lib/graphql_rails/controller/request.rb
195
190
  - lib/graphql_rails/controller/request/format_errors.rb
@@ -209,10 +204,10 @@ files:
209
204
  - lib/graphql_rails/model/build_connection_type.rb
210
205
  - lib/graphql_rails/model/build_connection_type/count_items.rb
211
206
  - lib/graphql_rails/model/build_enum_type.rb
212
- - lib/graphql_rails/model/build_graphql_input_type.rb
213
207
  - lib/graphql_rails/model/call_graphql_model_method.rb
214
208
  - lib/graphql_rails/model/configurable.rb
215
209
  - lib/graphql_rails/model/configuration.rb
210
+ - lib/graphql_rails/model/find_or_build_graphql_input_type.rb
216
211
  - lib/graphql_rails/model/find_or_build_graphql_type.rb
217
212
  - lib/graphql_rails/model/find_or_build_graphql_type_class.rb
218
213
  - lib/graphql_rails/model/input.rb
@@ -220,13 +215,13 @@ files:
220
215
  - lib/graphql_rails/railtie.rb
221
216
  - lib/graphql_rails/router.rb
222
217
  - lib/graphql_rails/router/build_schema_action_type.rb
218
+ - lib/graphql_rails/router/event_route.rb
223
219
  - lib/graphql_rails/router/mutation_route.rb
224
220
  - lib/graphql_rails/router/plain_cursor_encoder.rb
225
221
  - lib/graphql_rails/router/query_route.rb
226
222
  - lib/graphql_rails/router/resource_routes_builder.rb
227
223
  - lib/graphql_rails/router/route.rb
228
224
  - lib/graphql_rails/router/schema_builder.rb
229
- - lib/graphql_rails/router/subscription_route.rb
230
225
  - lib/graphql_rails/rspec_controller_helpers.rb
231
226
  - lib/graphql_rails/tasks/dump_graphql_schema.rb
232
227
  - lib/graphql_rails/tasks/dump_graphql_schemas.rb
@@ -234,6 +229,7 @@ files:
234
229
  - lib/graphql_rails/types/argument_type.rb
235
230
  - lib/graphql_rails/types/field_type.rb
236
231
  - lib/graphql_rails/types/hidable_by_group.rb
232
+ - lib/graphql_rails/types/input_object_type.rb
237
233
  - lib/graphql_rails/types/object_type.rb
238
234
  - lib/graphql_rails/version.rb
239
235
  homepage: https://github.com/samesystem/graphql_rails
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'graphql_rails/types/argument_type'
4
- require 'graphql_rails/concerns/service'
5
-
6
- module GraphqlRails
7
- module Model
8
- # stores information about model specific config, like attributes and types
9
- class BuildGraphqlInputType
10
- include ::GraphqlRails::Service
11
-
12
- def initialize(name:, description: nil, attributes:)
13
- @name = name
14
- @attributes = attributes
15
- @description = description
16
- end
17
-
18
- def call
19
- type_name = name
20
- type_description = description
21
- type_attributes = attributes
22
-
23
- Class.new(GraphQL::Schema::InputObject) do
24
- argument_class(GraphqlRails::Types::ArgumentType)
25
- graphql_name(type_name)
26
- description(type_description)
27
-
28
- type_attributes.each_value do |type_attribute|
29
- argument(*type_attribute.input_argument_args, **type_attribute.input_argument_options)
30
- end
31
-
32
- def self.inspect
33
- "#{GraphQL::Schema::InputObject}(#{graphql_name})"
34
- end
35
- end
36
- end
37
-
38
- private
39
-
40
- attr_reader :model_configuration, :attributes, :name, :description
41
- end
42
- end
43
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'route'
4
-
5
- module GraphqlRails
6
- class Router
7
- # stores subscription type graphql action info
8
- class SubscriptionRoute < Route
9
- def query?
10
- false
11
- end
12
-
13
- def mutation?
14
- false
15
- end
16
-
17
- def subscription?
18
- true
19
- end
20
- end
21
- end
22
- end