graphql_rails 2.3.0 → 2.4.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +3 -2
  3. data/CHANGELOG.md +8 -0
  4. data/Gemfile.lock +16 -16
  5. data/docs/README.md +1 -1
  6. data/docs/components/model.md +38 -5
  7. data/docs/components/routes.md +20 -10
  8. data/graphql_rails.gemspec +1 -1
  9. data/lib/generators/graphql_rails/templates/graphql_controller.erb +1 -1
  10. data/lib/graphql_rails/attributes/attribute.rb +9 -1
  11. data/lib/graphql_rails/attributes/attribute_configurable.rb +9 -0
  12. data/lib/graphql_rails/attributes/attribute_name_parser.rb +4 -4
  13. data/lib/graphql_rails/attributes/input_attribute.rb +2 -1
  14. data/lib/graphql_rails/attributes/type_parseable.rb +4 -5
  15. data/lib/graphql_rails/controller/action_configuration.rb +1 -1
  16. data/lib/graphql_rails/controller/configuration.rb +1 -1
  17. data/lib/graphql_rails/controller/request/format_errors.rb +1 -1
  18. data/lib/graphql_rails/controller/request.rb +3 -2
  19. data/lib/graphql_rails/decorator/relation_decorator.rb +2 -2
  20. data/lib/graphql_rails/errors/custom_execution_error.rb +1 -1
  21. data/lib/graphql_rails/errors/execution_error.rb +1 -1
  22. data/lib/graphql_rails/model/find_or_build_graphql_input_type.rb +28 -0
  23. data/lib/graphql_rails/model/find_or_build_graphql_type.rb +14 -5
  24. data/lib/graphql_rails/model/find_or_build_graphql_type_class.rb +4 -3
  25. data/lib/graphql_rails/model/input.rb +3 -3
  26. data/lib/graphql_rails/router/event_route.rb +52 -0
  27. data/lib/graphql_rails/router/mutation_route.rb +1 -1
  28. data/lib/graphql_rails/router/query_route.rb +1 -1
  29. data/lib/graphql_rails/router/resource_routes_builder.rb +0 -8
  30. data/lib/graphql_rails/router/route.rb +1 -1
  31. data/lib/graphql_rails/router/schema_builder.rb +15 -10
  32. data/lib/graphql_rails/router.rb +8 -8
  33. data/lib/graphql_rails/rspec_controller_helpers.rb +3 -1
  34. data/lib/graphql_rails/types/hidable_by_group.rb +23 -3
  35. data/lib/graphql_rails/types/input_object_type.rb +16 -0
  36. data/lib/graphql_rails/version.rb +1 -1
  37. metadata +9 -14
  38. data/lib/graphql_rails/model/build_graphql_input_type.rb +0 -43
  39. data/lib/graphql_rails/router/subscription_route.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f06459a3c8c16e40dffd181d7c08128558e2bdca598845b9e94f51852681e61
4
- data.tar.gz: 1a4ddc9e11a4c5ef22240f7e36b3070bcf89b712c561cad12e41ede1dc18fbc3
3
+ metadata.gz: 9ef0115ce3d9107ee48ec4e7a725baff242ce81133be4a955d0a81619b106192
4
+ data.tar.gz: dcb027f23eb5f6cd71b3144e2794822ee899796a5e40f7b240ea3cd59ef586b9
5
5
  SHA512:
6
- metadata.gz: 23e0d160c19e3c56c00a474cb77eff10c6a86c3ce1c63f3cdb87f4c374f3c10da79b5f2529a14a026f81e6f3b2c32e9b2fecd671bd7b38066e07d020c65fa93a
7
- data.tar.gz: a0ade6d1ce611baf97ab0a631770273c98953b04eb3991e3234c12a12f21e893962b62a1785ba5da48de7193c366129d29732c7121fbe6c4404d5e1f05cedda2
6
+ metadata.gz: 8282983f1215feffb37e0541680abd91a44799a95d687cb3adb5cfcb91a1adbf8a07d585fffcd4e477579eebdd9f4a09f0efbc6dfb0b264b0a1a288aa0ac9688
7
+ data.tar.gz: f7cafd9924e8e26abc9a6e5783938ebedbea7a0dd68fc69a5980186affab6593f8af4a25c8205e20fbfb45534bec96aa4b5b36bc558084994200a73f8eca31d7
@@ -3,14 +3,15 @@ on: [push, pull_request]
3
3
  jobs:
4
4
  specs:
5
5
  strategy:
6
+ fail-fast: false
6
7
  matrix:
7
- ruby-version: ['2.7', '3.0', '3.1']
8
+ ruby-version: ['2.7', '3.0', '3.1', '3.2']
8
9
 
9
10
  runs-on: ubuntu-latest
10
11
  env:
11
12
  CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
12
13
  steps:
13
- - uses: actions/checkout@v2
14
+ - uses: actions/checkout@v3
14
15
  - uses: ruby/setup-ruby@v1
15
16
  with:
16
17
  ruby-version: ${{ matrix.ruby-version }}
data/CHANGELOG.md CHANGED
@@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  * Added/Changed/Deprecated/Removed/Fixed/Security: YOUR CHANGE HERE
11
11
 
12
+ ## [2.4.0](2023-27-25)
13
+
14
+ * Added: `hidden_in_groups` for attributes to be able to skip attribute from certain groups
15
+ * Added: `extras` for attributes to be able to include graphql-ruby extensions
16
+ * Added: `lookahead` as a controller request object field
17
+ * Changed: `subscription` definition to `event` definition in router configuration page
18
+ * Fixed: avoid "Found two visible definitions for X" issues for input types
19
+
12
20
  ## [2.3.0](2022-11-25)
13
21
 
14
22
  * Added support for Ruby 3.1.2, keyword arguments for decorators support included
data/Gemfile.lock CHANGED
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- graphql_rails (2.3.0)
4
+ graphql_rails (2.4.0)
5
5
  activesupport (>= 4)
6
- graphql (~> 1.12, >= 1.12.4)
6
+ graphql (= 2.0.21)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
@@ -74,17 +74,17 @@ GEM
74
74
  codecov (0.6.0)
75
75
  simplecov (>= 0.15, < 0.22)
76
76
  coderay (1.1.3)
77
- concurrent-ruby (1.1.9)
77
+ concurrent-ruby (1.1.10)
78
78
  crass (1.0.6)
79
79
  diff-lcs (1.5.0)
80
80
  docile (1.4.0)
81
81
  erubi (1.10.0)
82
- globalid (1.0.0)
82
+ globalid (1.0.1)
83
83
  activesupport (>= 5.0)
84
- graphql (1.13.17)
85
- i18n (1.8.11)
84
+ graphql (2.0.21)
85
+ i18n (1.12.0)
86
86
  concurrent-ruby (~> 1.0)
87
- loofah (2.18.0)
87
+ loofah (2.19.1)
88
88
  crass (~> 1.0.2)
89
89
  nokogiri (>= 1.5.9)
90
90
  mail (2.7.1)
@@ -92,8 +92,8 @@ GEM
92
92
  marcel (1.0.2)
93
93
  method_source (1.0.0)
94
94
  mini_mime (1.1.2)
95
- mini_portile2 (2.8.0)
96
- minitest (5.15.0)
95
+ mini_portile2 (2.8.1)
96
+ minitest (5.17.0)
97
97
  mongo (2.17.0)
98
98
  bson (>= 4.8.2, < 5.0.0)
99
99
  mongoid (7.3.3)
@@ -101,7 +101,7 @@ GEM
101
101
  mongo (>= 2.10.5, < 3.0.0)
102
102
  ruby2_keywords (~> 0.0.5)
103
103
  nio4r (2.5.8)
104
- nokogiri (1.13.9)
104
+ nokogiri (1.14.3)
105
105
  mini_portile2 (~> 2.8.0)
106
106
  racc (~> 1.4)
107
107
  parallel (1.21.0)
@@ -113,8 +113,8 @@ GEM
113
113
  pry-byebug (3.9.0)
114
114
  byebug (~> 11.0)
115
115
  pry (~> 0.13.0)
116
- racc (1.6.0)
117
- rack (2.2.3.1)
116
+ racc (1.6.2)
117
+ rack (2.2.6.4)
118
118
  rack-test (1.1.0)
119
119
  rack (>= 1.0, < 3)
120
120
  rails (6.1.4.4)
@@ -135,8 +135,8 @@ GEM
135
135
  rails-dom-testing (2.0.3)
136
136
  activesupport (>= 4.2.0)
137
137
  nokogiri (>= 1.6)
138
- rails-html-sanitizer (1.4.3)
139
- loofah (~> 2.3)
138
+ rails-html-sanitizer (1.4.4)
139
+ loofah (~> 2.19, >= 2.19.1)
140
140
  railties (6.1.4.4)
141
141
  actionpack (= 6.1.4.4)
142
142
  activesupport (= 6.1.4.4)
@@ -193,13 +193,13 @@ GEM
193
193
  activesupport (>= 5.2)
194
194
  sprockets (>= 3.0.0)
195
195
  thor (1.2.1)
196
- tzinfo (2.0.4)
196
+ tzinfo (2.0.5)
197
197
  concurrent-ruby (~> 1.0)
198
198
  unicode-display_width (1.8.0)
199
199
  websocket-driver (0.7.5)
200
200
  websocket-extensions (>= 0.1.0)
201
201
  websocket-extensions (0.1.5)
202
- zeitwerk (2.5.3)
202
+ zeitwerk (2.6.6)
203
203
 
204
204
  PLATFORMS
205
205
  ruby
data/docs/README.md CHANGED
@@ -92,7 +92,7 @@ class Graphql::UsersController < GraphqlApplicationController
92
92
  end
93
93
  ```
94
94
 
95
- See [Controller docs](components/controlle.md) for more info.
95
+ See [Controller docs](components/controller.md) for more info.
96
96
 
97
97
  ## Testing your GraphqlRails::Controller in RSpec
98
98
 
@@ -101,7 +101,7 @@ Check [graphql-ruby documentation](https://graphql-ruby.org) for more details ab
101
101
 
102
102
  ### attribute.property
103
103
 
104
- By default graphql attribute names are expected to be same as model methods/attributes, but if you want to use different name on grapqhl side, you can use `property` option:
104
+ By default graphql attribute names are expected to be same as model methods/attributes, but if you want to use different name on graphql side, you can use `property` option:
105
105
 
106
106
  ```ruby
107
107
  class User
@@ -185,6 +185,24 @@ class User
185
185
  end
186
186
  ```
187
187
 
188
+ ### attribute.hidden_in_groups
189
+
190
+ Opposite for Attribute#groups. It hides attribute in given groups
191
+
192
+ ```ruby
193
+ class User
194
+ include GraphqlRails::Model
195
+
196
+ graphql do |c|
197
+ # visible in all schemas (default):
198
+ c.attribute(:email)
199
+
200
+ # visible in all schemas except "external":
201
+ c.attribute(:nickname).hidden_in_groups(:external)
202
+ end
203
+ end
204
+ ```
205
+
188
206
  ### attribute.options
189
207
 
190
208
  Allows passing options to attribute definition. Available options:
@@ -200,6 +218,21 @@ class User
200
218
  c.attribute :first_name, options: { attribute_name_format: :original } # will be accessible as first_name from client side
201
219
  end
202
220
  end
221
+ ```
222
+
223
+ ### attribute.extras
224
+
225
+ Allows passing extras to enable [graphql-ruby field extensions](https://graphql-ruby.org/type_definitions/field_extensions.html#using-extras)
226
+
227
+ ```ruby
228
+ class User
229
+ include GraphqlRails::Model
230
+
231
+ graphql do |c|
232
+ c.attribute(:items).extras([:lookahead])
233
+ end
234
+ end
235
+ ```
203
236
 
204
237
  ### attribute.permit
205
238
 
@@ -303,7 +336,7 @@ You can mark collection method as `paginated`. In this case method will return r
303
336
  class User
304
337
  include GraphqlRails::Model
305
338
 
306
- graphql.attribute :items, type: '[Item]', paginatted: true
339
+ graphql.attribute :items, type: '[Item]', paginated: true
307
340
 
308
341
  def items
309
342
  Item.all
@@ -388,7 +421,7 @@ end
388
421
 
389
422
  ## name
390
423
 
391
- By default grapqhl type name will be same as model name, but you can change it via `name` method
424
+ By default graphql type name will be same as model name, but you can change it via `name` method
392
425
 
393
426
  ```ruby
394
427
  class User
@@ -402,7 +435,7 @@ end
402
435
 
403
436
  ## description
404
437
 
405
- To improve grapqhl documentation, you can description for your graphql type:
438
+ To improve graphql documentation, you can description for your graphql type:
406
439
 
407
440
  ```ruby
408
441
  class User
@@ -419,7 +452,7 @@ end
419
452
  Sometimes it's handy to get raw graphql type. To do so you can call:
420
453
 
421
454
  ```ruby
422
- YourModel.graphql.grapqhl_type
455
+ YourModel.graphql.graphql_type
423
456
  ```
424
457
 
425
458
  ## input
@@ -21,10 +21,10 @@ MyGraphqlSchema = GraphqlRails::Router.draw do
21
21
 
22
22
  # you can use namespaced controllers too:
23
23
  scope module: 'admin' do
24
- # `updateTranslations` route will be handeled by `Admin::TranslationsController`
24
+ # `updateTranslations` route will be handled by `Admin::TranslationsController`
25
25
  mutation :updateTranslations, to: 'translations#update'
26
26
 
27
- # all :groups routes will be handeled by `Admin::GroupsController`
27
+ # all :groups routes will be handled by `Admin::GroupsController`
28
28
  resources :groups
29
29
  end
30
30
  end
@@ -40,9 +40,9 @@ If you want to exclude some actions you can use `only` or `except` options.
40
40
 
41
41
  ```ruby
42
42
  MyGraphqlSchema = GraphqlRails::Router.draw do
43
- resouces :users
44
- resouces :friends, only: :index
45
- resouces :posts, except: [:destroy, :index]
43
+ resources :users
44
+ resources :friends, only: :index
45
+ resources :posts, except: [:destroy, :index]
46
46
  end
47
47
  ```
48
48
 
@@ -52,7 +52,7 @@ Sometimes it's handy so have non-CRUD actions in your controller. To define such
52
52
 
53
53
  ```ruby
54
54
  MyGraphqlSchema = GraphqlRails::Router.draw do
55
- resouces :users do
55
+ resources :users do
56
56
  mutation :changePassword, on: :member
57
57
  query :active, on: :collection
58
58
  end
@@ -65,7 +65,7 @@ Sometimes, especially when working with member queries, it sounds better when ac
65
65
 
66
66
  ```ruby
67
67
  MyGraphqlSchema = GraphqlRails::Router.draw do
68
- resouces :users do
68
+ resources :users do
69
69
  query :details, on: :member, suffix: true
70
70
  end
71
71
  end
@@ -73,15 +73,25 @@ end
73
73
 
74
74
  This will generate `userDetails` field on GraphQL side.
75
75
 
76
- ## _query_ and _mutation_ & _subscription_
76
+ ## _query_ and _mutation_ & _event_
77
+
78
+ In case you want to have non-CRUD controller with custom actions you can define your own `query`/`mutation` actions like this:
79
+
80
+ ```ruby
81
+ MyGraphqlSchema = GraphqlRails::Router.draw do
82
+ mutation :logIn, to: 'sessions#login'
83
+ query :me, to: 'users#current_user'
84
+ end
77
85
 
78
- in case you want to have non-CRUD controller with custom actions you can define your own `query`/`mutation`/`subscription` actions like this:
86
+ Subscriptions are not really controller actions with a single response type, thus, they're defined differently. In GraphQL you subscribe to event, for example `userCreated`. To do this in graphql_rails you would define `event :user_created` in router definition.
79
87
 
80
88
  ```ruby
81
89
  MyGraphqlSchema = GraphqlRails::Router.draw do
82
90
  mutation :logIn, to: 'sessions#login'
83
91
  query :me, to: 'users#current_user'
84
- subscribtion :new_message, to: 'messages#created'
92
+
93
+ event :user_created # expects Subscriptions::UserCreatedSubscription class to be present
94
+ event :user_deleted, subscription_class: 'Subscriptions::UserDeletedSubscription'
85
95
  end
86
96
  ```
87
97
 
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ['lib']
22
22
 
23
- spec.add_dependency 'graphql', '~> 1.12', '>= 1.12.4'
23
+ spec.add_dependency 'graphql', '2.0.21'
24
24
  spec.add_dependency 'activesupport', '>= 4'
25
25
 
26
26
  spec.add_development_dependency 'bundler', '~> 2'
@@ -12,7 +12,7 @@ class GraphqlController < ApplicationController
12
12
 
13
13
  private
14
14
 
15
- # data defined here will be accessible via `grapqhl_request.context`
15
+ # data defined here will be accessible via `graphql_request.context`
16
16
  # in GraphqlRails::Controller instances
17
17
  def graphql_context
18
18
  {}
@@ -42,7 +42,9 @@ module GraphqlRails
42
42
  null: optional?,
43
43
  camelize: camelize?,
44
44
  groups: groups,
45
- **deprecation_reason_params
45
+ hidden_in_groups: hidden_in_groups,
46
+ **deprecation_reason_params,
47
+ **extras_options
46
48
  }
47
49
  end
48
50
 
@@ -52,6 +54,12 @@ module GraphqlRails
52
54
 
53
55
  private
54
56
 
57
+ def extras_options
58
+ return {} if extras.empty?
59
+
60
+ { extras: extras }
61
+ end
62
+
55
63
  def camelize?
56
64
  options[:input_format] != :original && options[:attribute_name_format] != :original
57
65
  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
@@ -3,7 +3,7 @@
3
3
  module GraphqlRails
4
4
  module Attributes
5
5
  # Parses attribute name and can generates graphql scalar type,
6
- # grapqhl name and etc. based on that
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
- preprocesed_name
16
+ preprocessed_name
17
17
  else
18
- preprocesed_name.camelize(:lower)
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 preprocesed_name
50
+ def preprocessed_name
51
51
  if name.end_with?('?')
52
52
  "is_#{name.remove(/\?\Z/)}"
53
53
  else
@@ -31,6 +31,7 @@ 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,
35
36
  **deprecation_reason_params
36
37
  }
@@ -79,7 +80,7 @@ module GraphqlRails
79
80
  end
80
81
 
81
82
  def raw_input_type
82
- return type if type.is_a?(GraphQL::InputObjectType)
83
+ return type if type.is_a?(GraphQL::Schema::InputObject)
83
84
  return type.graphql_input_type if type.is_a?(Model::Input)
84
85
  end
85
86
  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::BaseType,
51
- GraphQL::ObjectType,
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
@@ -7,7 +7,7 @@ require 'graphql_rails/errors/error'
7
7
 
8
8
  module GraphqlRails
9
9
  class Controller
10
- # stores all graphql_rails contoller specific config
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
@@ -7,7 +7,7 @@ require 'graphql_rails/errors/error'
7
7
 
8
8
  module GraphqlRails
9
9
  class Controller
10
- # stores all graphql_rails contoller specific config
10
+ # stores all graphql_rails controller specific config
11
11
  class Configuration
12
12
  class InvalidActionConfiguration < GraphqlRails::Error; end
13
13
 
@@ -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 meaningfull graphql error classes
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
 
@@ -2,10 +2,10 @@
2
2
 
3
3
  module GraphqlRails
4
4
  module Decorator
5
- # wrapps active record relation and returns decorated object instead
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 tructure
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 tructure
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)
@@ -0,0 +1,28 @@
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
+ end
27
+ end
28
+ end
@@ -19,7 +19,7 @@ module GraphqlRails
19
19
  end
20
20
 
21
21
  def call
22
- klass.tap { add_fields_to_graphql_type if new_class? || force_define_attributes }
22
+ klass.tap { add_attributes if new_class? || force_define_attributes }
23
23
  end
24
24
 
25
25
  private
@@ -28,20 +28,29 @@ module GraphqlRails
28
28
 
29
29
  delegate :klass, :new_class?, to: :type_class_finder
30
30
 
31
+ def parent_class
32
+ GraphqlRails::Types::ObjectType
33
+ end
34
+
35
+ def add_attributes_batch(attributes)
36
+ AddFieldsToGraphqlType.call(klass: klass, attributes: attributes)
37
+ end
38
+
31
39
  def type_class_finder
32
40
  @type_class_finder ||= FindOrBuildGraphqlTypeClass.new(
33
41
  name: name,
34
42
  type_name: type_name,
35
- description: description
43
+ description: description,
44
+ parent_class: parent_class
36
45
  )
37
46
  end
38
47
 
39
- def add_fields_to_graphql_type
48
+ def add_attributes
40
49
  scalar_attributes, dynamic_attributes = attributes.values.partition(&:scalar_type?)
41
50
 
42
- AddFieldsToGraphqlType.call(klass: klass, attributes: scalar_attributes)
51
+ add_attributes_batch(scalar_attributes)
43
52
  dynamic_attributes.each { |attribute| find_or_build_dynamic_type(attribute) }
44
- AddFieldsToGraphqlType.call(klass: klass, attributes: dynamic_attributes)
53
+ add_attributes_batch(dynamic_attributes)
45
54
  end
46
55
 
47
56
  def find_or_build_dynamic_type(attribute)
@@ -9,11 +9,12 @@ 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)
13
13
  @name = name
14
14
  @type_name = type_name
15
15
  @description = description
16
16
  @new_class = false
17
+ @parent_class = parent_class
17
18
  end
18
19
 
19
20
  def klass
@@ -27,13 +28,13 @@ module GraphqlRails
27
28
  private
28
29
 
29
30
  attr_accessor :new_class
30
- attr_reader :name, :type_name, :description
31
+ attr_reader :name, :type_name, :description, :parent_class
31
32
 
32
33
  def build_graphql_type_klass
33
34
  graphql_type_name = name
34
35
  graphql_type_description = description
35
36
 
36
- graphql_type_klass = Class.new(GraphqlRails::Types::ObjectType) do
37
+ graphql_type_klass = Class.new(parent_class) do
37
38
  graphql_name(graphql_type_name)
38
39
  description(graphql_type_description)
39
40
  end
@@ -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
@@ -38,7 +38,7 @@ module GraphqlRails
38
38
  if function
39
39
  { function: function }
40
40
  else
41
- { resolver: resolver }
41
+ { resolver: resolver, extras: [:lookahead] }
42
42
  end
43
43
  end
44
44
 
@@ -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)
@@ -95,7 +95,9 @@ module GraphqlRails
95
95
  # controller request object more suitable for testing
96
96
  class Request < GraphqlRails::Controller::Request
97
97
  def initialize(params, context)
98
- super(nil, params, context)
98
+ inputs = params || {}
99
+ inputs = inputs.merge(lookahead: ::GraphQL::Execution::Lookahead::NullLookahead.new)
100
+ super(nil, inputs, context)
99
101
  end
100
102
  end
101
103
 
@@ -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 = '2.4.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: 2.4.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: 2023-07-25 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.0.21
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.0.21
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: activesupport
35
29
  requirement: !ruby/object:Gem::Requirement
@@ -209,10 +203,10 @@ files:
209
203
  - lib/graphql_rails/model/build_connection_type.rb
210
204
  - lib/graphql_rails/model/build_connection_type/count_items.rb
211
205
  - lib/graphql_rails/model/build_enum_type.rb
212
- - lib/graphql_rails/model/build_graphql_input_type.rb
213
206
  - lib/graphql_rails/model/call_graphql_model_method.rb
214
207
  - lib/graphql_rails/model/configurable.rb
215
208
  - lib/graphql_rails/model/configuration.rb
209
+ - lib/graphql_rails/model/find_or_build_graphql_input_type.rb
216
210
  - lib/graphql_rails/model/find_or_build_graphql_type.rb
217
211
  - lib/graphql_rails/model/find_or_build_graphql_type_class.rb
218
212
  - lib/graphql_rails/model/input.rb
@@ -220,13 +214,13 @@ files:
220
214
  - lib/graphql_rails/railtie.rb
221
215
  - lib/graphql_rails/router.rb
222
216
  - lib/graphql_rails/router/build_schema_action_type.rb
217
+ - lib/graphql_rails/router/event_route.rb
223
218
  - lib/graphql_rails/router/mutation_route.rb
224
219
  - lib/graphql_rails/router/plain_cursor_encoder.rb
225
220
  - lib/graphql_rails/router/query_route.rb
226
221
  - lib/graphql_rails/router/resource_routes_builder.rb
227
222
  - lib/graphql_rails/router/route.rb
228
223
  - lib/graphql_rails/router/schema_builder.rb
229
- - lib/graphql_rails/router/subscription_route.rb
230
224
  - lib/graphql_rails/rspec_controller_helpers.rb
231
225
  - lib/graphql_rails/tasks/dump_graphql_schema.rb
232
226
  - lib/graphql_rails/tasks/dump_graphql_schemas.rb
@@ -234,6 +228,7 @@ files:
234
228
  - lib/graphql_rails/types/argument_type.rb
235
229
  - lib/graphql_rails/types/field_type.rb
236
230
  - lib/graphql_rails/types/hidable_by_group.rb
231
+ - lib/graphql_rails/types/input_object_type.rb
237
232
  - lib/graphql_rails/types/object_type.rb
238
233
  - lib/graphql_rails/version.rb
239
234
  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