graphql_rails 2.3.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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