graphql_rails 2.4.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +1 -1
- data/CHANGELOG.md +14 -1
- data/Gemfile.lock +72 -69
- data/docs/components/controller.md +15 -1
- data/docs/components/model.md +92 -1
- data/graphql_rails.gemspec +1 -1
- data/lib/graphql_rails/attributes/attributable.rb +6 -0
- data/lib/graphql_rails/attributes/attribute.rb +13 -8
- data/lib/graphql_rails/attributes/attribute_configurable.rb +18 -0
- data/lib/graphql_rails/attributes/input_attribute.rb +5 -0
- data/lib/graphql_rails/attributes/type_parseable.rb +2 -2
- data/lib/graphql_rails/controller/action.rb +4 -4
- data/lib/graphql_rails/controller/build_controller_action_resolver.rb +4 -15
- data/lib/graphql_rails/controller/configuration.rb +6 -1
- 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.rb +9 -6
- data/lib/graphql_rails/model/configuration.rb +15 -2
- data/lib/graphql_rails/model/find_or_build_graphql_input_type.rb +8 -0
- data/lib/graphql_rails/model/find_or_build_graphql_type.rb +34 -9
- data/lib/graphql_rails/model/find_or_build_graphql_type_class.rb +5 -2
- data/lib/graphql_rails/router/route.rb +12 -2
- data/lib/graphql_rails/rspec_controller_helpers.rb +14 -2
- data/lib/graphql_rails/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47c75badc8873658f461e2bc0f6de0ca35f2c13c7ded2ed66b23b20ee91fc60e
|
4
|
+
data.tar.gz: 551a92383fad945d6fb8c03f190793431b485a8a98256a64e26f892c1e48fc2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e852e9c89ee080ca786abfaabea1162d8ed1eadb4086bf7d2f9908c454e56dc8c839ab05f6a3967859188f3c36f32eae1907b45e41476e24fb81f5fb5db8e29
|
7
|
+
data.tar.gz: 0d970a75c022b4635e6c925db92f8d7d22cc67b8e8e41ed8c961c98b2a8aa2c3b4726a29fc736af5151ea935c899b21d454e9af703e9beb6ea9fab378d5fecbf
|
data/.github/workflows/ruby.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -9,7 +9,20 @@ 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
|
-
## [
|
12
|
+
## [3.0.0](2024-05-31)
|
13
|
+
|
14
|
+
* Added: `input.attribute.property` method which allows aliasing input parameter keys
|
15
|
+
* Added: possibility to copy attribute config using the `Attribute#same_as` method
|
16
|
+
* Fixed: do not ignore custom `max_page_size` for paginated responses
|
17
|
+
* Fixed: do not ignore custom `default_page_size` and other options for paginated responses
|
18
|
+
* Fixed: do not crash when using deeply nested input definitions
|
19
|
+
* Added: `rescue_from` support in controllers
|
20
|
+
* Added: Bumped graphql version to 2.1.7
|
21
|
+
* Added: `implements` support in models
|
22
|
+
* Added: `response.controller` and `response.action_name` methods in RSpecControllerHelpers
|
23
|
+
* Removed: stop supporting ruby < 3.0.0
|
24
|
+
|
25
|
+
## [2.4.0](2023-11-25)
|
13
26
|
|
14
27
|
* Added: `hidden_in_groups` for attributes to be able to skip attribute from certain groups
|
15
28
|
* Added: `extras` for attributes to be able to include graphql-ruby extensions
|
data/Gemfile.lock
CHANGED
@@ -1,67 +1,67 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
graphql_rails (
|
4
|
+
graphql_rails (3.0.0)
|
5
5
|
activesupport (>= 4)
|
6
|
-
graphql (= 2.
|
6
|
+
graphql (= 2.1.7)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
actioncable (6.1.
|
12
|
-
actionpack (= 6.1.
|
13
|
-
activesupport (= 6.1.
|
11
|
+
actioncable (6.1.7.1)
|
12
|
+
actionpack (= 6.1.7.1)
|
13
|
+
activesupport (= 6.1.7.1)
|
14
14
|
nio4r (~> 2.0)
|
15
15
|
websocket-driver (>= 0.6.1)
|
16
|
-
actionmailbox (6.1.
|
17
|
-
actionpack (= 6.1.
|
18
|
-
activejob (= 6.1.
|
19
|
-
activerecord (= 6.1.
|
20
|
-
activestorage (= 6.1.
|
21
|
-
activesupport (= 6.1.
|
16
|
+
actionmailbox (6.1.7.1)
|
17
|
+
actionpack (= 6.1.7.1)
|
18
|
+
activejob (= 6.1.7.1)
|
19
|
+
activerecord (= 6.1.7.1)
|
20
|
+
activestorage (= 6.1.7.1)
|
21
|
+
activesupport (= 6.1.7.1)
|
22
22
|
mail (>= 2.7.1)
|
23
|
-
actionmailer (6.1.
|
24
|
-
actionpack (= 6.1.
|
25
|
-
actionview (= 6.1.
|
26
|
-
activejob (= 6.1.
|
27
|
-
activesupport (= 6.1.
|
23
|
+
actionmailer (6.1.7.1)
|
24
|
+
actionpack (= 6.1.7.1)
|
25
|
+
actionview (= 6.1.7.1)
|
26
|
+
activejob (= 6.1.7.1)
|
27
|
+
activesupport (= 6.1.7.1)
|
28
28
|
mail (~> 2.5, >= 2.5.4)
|
29
29
|
rails-dom-testing (~> 2.0)
|
30
|
-
actionpack (6.1.
|
31
|
-
actionview (= 6.1.
|
32
|
-
activesupport (= 6.1.
|
30
|
+
actionpack (6.1.7.1)
|
31
|
+
actionview (= 6.1.7.1)
|
32
|
+
activesupport (= 6.1.7.1)
|
33
33
|
rack (~> 2.0, >= 2.0.9)
|
34
34
|
rack-test (>= 0.6.3)
|
35
35
|
rails-dom-testing (~> 2.0)
|
36
36
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
37
|
-
actiontext (6.1.
|
38
|
-
actionpack (= 6.1.
|
39
|
-
activerecord (= 6.1.
|
40
|
-
activestorage (= 6.1.
|
41
|
-
activesupport (= 6.1.
|
37
|
+
actiontext (6.1.7.1)
|
38
|
+
actionpack (= 6.1.7.1)
|
39
|
+
activerecord (= 6.1.7.1)
|
40
|
+
activestorage (= 6.1.7.1)
|
41
|
+
activesupport (= 6.1.7.1)
|
42
42
|
nokogiri (>= 1.8.5)
|
43
|
-
actionview (6.1.
|
44
|
-
activesupport (= 6.1.
|
43
|
+
actionview (6.1.7.1)
|
44
|
+
activesupport (= 6.1.7.1)
|
45
45
|
builder (~> 3.1)
|
46
46
|
erubi (~> 1.4)
|
47
47
|
rails-dom-testing (~> 2.0)
|
48
48
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
49
|
-
activejob (6.1.
|
50
|
-
activesupport (= 6.1.
|
49
|
+
activejob (6.1.7.1)
|
50
|
+
activesupport (= 6.1.7.1)
|
51
51
|
globalid (>= 0.3.6)
|
52
|
-
activemodel (6.1.
|
53
|
-
activesupport (= 6.1.
|
54
|
-
activerecord (6.1.
|
55
|
-
activemodel (= 6.1.
|
56
|
-
activesupport (= 6.1.
|
57
|
-
activestorage (6.1.
|
58
|
-
actionpack (= 6.1.
|
59
|
-
activejob (= 6.1.
|
60
|
-
activerecord (= 6.1.
|
61
|
-
activesupport (= 6.1.
|
62
|
-
marcel (~> 1.0
|
52
|
+
activemodel (6.1.7.1)
|
53
|
+
activesupport (= 6.1.7.1)
|
54
|
+
activerecord (6.1.7.1)
|
55
|
+
activemodel (= 6.1.7.1)
|
56
|
+
activesupport (= 6.1.7.1)
|
57
|
+
activestorage (6.1.7.1)
|
58
|
+
actionpack (= 6.1.7.1)
|
59
|
+
activejob (= 6.1.7.1)
|
60
|
+
activerecord (= 6.1.7.1)
|
61
|
+
activesupport (= 6.1.7.1)
|
62
|
+
marcel (~> 1.0)
|
63
63
|
mini_mime (>= 1.1.0)
|
64
|
-
activesupport (6.1.
|
64
|
+
activesupport (6.1.7.1)
|
65
65
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
66
66
|
i18n (>= 1.6, < 2)
|
67
67
|
minitest (>= 5.1)
|
@@ -74,15 +74,16 @@ 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
|
77
|
+
concurrent-ruby (1.3.1)
|
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
82
|
globalid (1.0.1)
|
83
83
|
activesupport (>= 5.0)
|
84
|
-
graphql (2.
|
85
|
-
|
84
|
+
graphql (2.1.7)
|
85
|
+
racc (~> 1.4)
|
86
|
+
i18n (1.14.5)
|
86
87
|
concurrent-ruby (~> 1.0)
|
87
88
|
loofah (2.19.1)
|
88
89
|
crass (~> 1.0.2)
|
@@ -92,8 +93,8 @@ GEM
|
|
92
93
|
marcel (1.0.2)
|
93
94
|
method_source (1.0.0)
|
94
95
|
mini_mime (1.1.2)
|
95
|
-
mini_portile2 (2.8.
|
96
|
-
minitest (5.
|
96
|
+
mini_portile2 (2.8.6)
|
97
|
+
minitest (5.23.1)
|
97
98
|
mongo (2.17.0)
|
98
99
|
bson (>= 4.8.2, < 5.0.0)
|
99
100
|
mongoid (7.3.3)
|
@@ -101,8 +102,8 @@ GEM
|
|
101
102
|
mongo (>= 2.10.5, < 3.0.0)
|
102
103
|
ruby2_keywords (~> 0.0.5)
|
103
104
|
nio4r (2.5.8)
|
104
|
-
nokogiri (1.
|
105
|
-
mini_portile2 (~> 2.8.
|
105
|
+
nokogiri (1.16.5)
|
106
|
+
mini_portile2 (~> 2.8.2)
|
106
107
|
racc (~> 1.4)
|
107
108
|
parallel (1.21.0)
|
108
109
|
parser (3.1.0.0)
|
@@ -113,40 +114,41 @@ GEM
|
|
113
114
|
pry-byebug (3.9.0)
|
114
115
|
byebug (~> 11.0)
|
115
116
|
pry (~> 0.13.0)
|
116
|
-
racc (1.
|
117
|
-
rack (2.2.
|
117
|
+
racc (1.8.0)
|
118
|
+
rack (2.2.9)
|
118
119
|
rack-test (1.1.0)
|
119
120
|
rack (>= 1.0, < 3)
|
120
|
-
rails (6.1.
|
121
|
-
actioncable (= 6.1.
|
122
|
-
actionmailbox (= 6.1.
|
123
|
-
actionmailer (= 6.1.
|
124
|
-
actionpack (= 6.1.
|
125
|
-
actiontext (= 6.1.
|
126
|
-
actionview (= 6.1.
|
127
|
-
activejob (= 6.1.
|
128
|
-
activemodel (= 6.1.
|
129
|
-
activerecord (= 6.1.
|
130
|
-
activestorage (= 6.1.
|
131
|
-
activesupport (= 6.1.
|
121
|
+
rails (6.1.7.1)
|
122
|
+
actioncable (= 6.1.7.1)
|
123
|
+
actionmailbox (= 6.1.7.1)
|
124
|
+
actionmailer (= 6.1.7.1)
|
125
|
+
actionpack (= 6.1.7.1)
|
126
|
+
actiontext (= 6.1.7.1)
|
127
|
+
actionview (= 6.1.7.1)
|
128
|
+
activejob (= 6.1.7.1)
|
129
|
+
activemodel (= 6.1.7.1)
|
130
|
+
activerecord (= 6.1.7.1)
|
131
|
+
activestorage (= 6.1.7.1)
|
132
|
+
activesupport (= 6.1.7.1)
|
132
133
|
bundler (>= 1.15.0)
|
133
|
-
railties (= 6.1.
|
134
|
+
railties (= 6.1.7.1)
|
134
135
|
sprockets-rails (>= 2.0.0)
|
135
136
|
rails-dom-testing (2.0.3)
|
136
137
|
activesupport (>= 4.2.0)
|
137
138
|
nokogiri (>= 1.6)
|
138
139
|
rails-html-sanitizer (1.4.4)
|
139
140
|
loofah (~> 2.19, >= 2.19.1)
|
140
|
-
railties (6.1.
|
141
|
-
actionpack (= 6.1.
|
142
|
-
activesupport (= 6.1.
|
141
|
+
railties (6.1.7.1)
|
142
|
+
actionpack (= 6.1.7.1)
|
143
|
+
activesupport (= 6.1.7.1)
|
143
144
|
method_source
|
144
|
-
rake (>=
|
145
|
+
rake (>= 12.2)
|
145
146
|
thor (~> 1.0)
|
146
147
|
rainbow (3.1.1)
|
147
148
|
rake (13.0.6)
|
148
149
|
regexp_parser (2.2.0)
|
149
|
-
rexml (3.2.
|
150
|
+
rexml (3.2.8)
|
151
|
+
strscan (>= 3.0.9)
|
150
152
|
rspec (3.10.0)
|
151
153
|
rspec-core (~> 3.10.0)
|
152
154
|
rspec-expectations (~> 3.10.0)
|
@@ -192,14 +194,15 @@ GEM
|
|
192
194
|
actionpack (>= 5.2)
|
193
195
|
activesupport (>= 5.2)
|
194
196
|
sprockets (>= 3.0.0)
|
197
|
+
strscan (3.1.0)
|
195
198
|
thor (1.2.1)
|
196
|
-
tzinfo (2.0.
|
199
|
+
tzinfo (2.0.6)
|
197
200
|
concurrent-ruby (~> 1.0)
|
198
201
|
unicode-display_width (1.8.0)
|
199
202
|
websocket-driver (0.7.5)
|
200
203
|
websocket-extensions (>= 0.1.0)
|
201
204
|
websocket-extensions (0.1.5)
|
202
|
-
zeitwerk (2.6.
|
205
|
+
zeitwerk (2.6.15)
|
203
206
|
|
204
207
|
PLATFORMS
|
205
208
|
ruby
|
@@ -194,7 +194,21 @@ class UsersController < GraphqlRails::Controller
|
|
194
194
|
action(:index).paginated(max_page_size: 10) # add max items limit
|
195
195
|
|
196
196
|
def index
|
197
|
-
User.all # it will render 10 users even you have more
|
197
|
+
User.all # it will render max 10 users even you have requested more
|
198
|
+
end
|
199
|
+
end
|
200
|
+
```
|
201
|
+
|
202
|
+
#### *default_page_size*
|
203
|
+
|
204
|
+
Allows to specify max items count per request
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
class UsersController < GraphqlRails::Controller
|
208
|
+
action(:index).paginated(default_page_size: 5) # add default items per page size
|
209
|
+
|
210
|
+
def index
|
211
|
+
User.all # it will render 5 users even you have more
|
198
212
|
end
|
199
213
|
end
|
200
214
|
```
|
data/docs/components/model.md
CHANGED
@@ -368,6 +368,21 @@ class User
|
|
368
368
|
end
|
369
369
|
```
|
370
370
|
|
371
|
+
### attribute.same_as
|
372
|
+
|
373
|
+
When you want to have identical attributes, you can use `Attribute#same_as` to make sure that attribute params will stay in sync:
|
374
|
+
|
375
|
+
```ruby
|
376
|
+
class User
|
377
|
+
include GraphqlRails::Model
|
378
|
+
|
379
|
+
graphql do |c|
|
380
|
+
c.attribute(:user_id).type('ID').description('User ID')
|
381
|
+
c.attribute(:person_id).same_as(c.attribute(:user_id))
|
382
|
+
end
|
383
|
+
end
|
384
|
+
```
|
385
|
+
|
371
386
|
### attribute.with
|
372
387
|
|
373
388
|
When you want to define some options dynamically, it's quite handy to use "Attribute#with" method:
|
@@ -447,6 +462,30 @@ class User
|
|
447
462
|
end
|
448
463
|
```
|
449
464
|
|
465
|
+
## implements
|
466
|
+
|
467
|
+
`implements` indicates that graphql type implements one or more interfaces:
|
468
|
+
|
469
|
+
```ruby
|
470
|
+
module UserInterface
|
471
|
+
include GraphQL::Schema::Interface
|
472
|
+
# ....
|
473
|
+
end
|
474
|
+
|
475
|
+
module AdvancedUserInterface
|
476
|
+
include GraphQL::Schema::Interface
|
477
|
+
# ...
|
478
|
+
end
|
479
|
+
|
480
|
+
class AdminUser
|
481
|
+
include GraphqlRails::Model
|
482
|
+
|
483
|
+
graphql do |c|
|
484
|
+
c.implements(UserInterface, AdvancedUserInterface)
|
485
|
+
end
|
486
|
+
end
|
487
|
+
```
|
488
|
+
|
450
489
|
## graphql_type
|
451
490
|
|
452
491
|
Sometimes it's handy to get raw graphql type. To do so you can call:
|
@@ -588,7 +627,6 @@ class User
|
|
588
627
|
end
|
589
628
|
```
|
590
629
|
|
591
|
-
|
592
630
|
#### input attribute deprecation
|
593
631
|
|
594
632
|
You can mark input attribute as deprecated with `deprecated` method:
|
@@ -618,6 +656,59 @@ class User
|
|
618
656
|
end
|
619
657
|
```
|
620
658
|
|
659
|
+
#### input attribute config copy
|
660
|
+
|
661
|
+
You can copy existing config from other attribute using `Attribute#same_as` method:
|
662
|
+
|
663
|
+
```ruby
|
664
|
+
class User
|
665
|
+
include GraphqlRails::Model
|
666
|
+
|
667
|
+
graphql.input(:create) do |c|
|
668
|
+
c.attribute(:first_name).type('String!')
|
669
|
+
c.attribute(:last_name).type('String!')
|
670
|
+
end
|
671
|
+
|
672
|
+
graphql.input(:update) do |c|
|
673
|
+
c.attribute(:id).type('ID!')
|
674
|
+
graphql.input(:contract).attributes.each_value do |attr|
|
675
|
+
c.attribute(attr.name).same_as(attr)
|
676
|
+
end
|
677
|
+
end
|
678
|
+
end
|
679
|
+
```
|
680
|
+
|
681
|
+
#### input attribute property
|
682
|
+
|
683
|
+
Sometimes it's handy to have different input attribute on graphql level and different on controller. That's when `Attribute#property` comes to the rescue:
|
684
|
+
|
685
|
+
```ruby
|
686
|
+
class Post
|
687
|
+
include GraphqlRails::Model
|
688
|
+
|
689
|
+
graphql.input do |c|
|
690
|
+
c.attribute(:author_id).type('ID').property(:user_id)
|
691
|
+
end
|
692
|
+
end
|
693
|
+
```
|
694
|
+
|
695
|
+
Then mutation such as:
|
696
|
+
|
697
|
+
```gql
|
698
|
+
mutation createPost(input: { authorId: 123 }) {
|
699
|
+
author
|
700
|
+
}
|
701
|
+
```
|
702
|
+
|
703
|
+
Will pass `user_id` instead of `authorId` in controller:
|
704
|
+
|
705
|
+
```ruby
|
706
|
+
# posts_controller.rb
|
707
|
+
def create
|
708
|
+
Post.create!(user_id: params[:input][:user_id])
|
709
|
+
end
|
710
|
+
```
|
711
|
+
|
621
712
|
## graphql_context
|
622
713
|
|
623
714
|
It's possible to access graphql_context in your model using method `graphql_context`:
|
data/graphql_rails.gemspec
CHANGED
@@ -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', '2.
|
23
|
+
spec.add_dependency 'graphql', '2.1.7'
|
24
24
|
spec.add_dependency 'activesupport', '>= 4'
|
25
25
|
|
26
26
|
spec.add_development_dependency 'bundler', '~> 2'
|
@@ -8,6 +8,12 @@ module GraphqlRails
|
|
8
8
|
# contains methods which are shared between various attribute-like classes
|
9
9
|
# expects `initial_name` and `type` to be defined
|
10
10
|
module Attributable
|
11
|
+
def initialize_copy(_original)
|
12
|
+
super
|
13
|
+
@attribute_name_parser = nil
|
14
|
+
@type_parser = nil
|
15
|
+
end
|
16
|
+
|
11
17
|
def field_name
|
12
18
|
attribute_name_parser.field_name
|
13
19
|
end
|
@@ -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
|
|
@@ -67,6 +61,17 @@ module GraphqlRails
|
|
67
61
|
def deprecation_reason_params
|
68
62
|
{ deprecation_reason: deprecation_reason }.compact
|
69
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
|
70
75
|
end
|
71
76
|
end
|
72
77
|
end
|
@@ -64,6 +64,24 @@ module GraphqlRails
|
|
64
64
|
def deprecation_reason
|
65
65
|
@deprecation_reason
|
66
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
|
67
85
|
end
|
68
86
|
end
|
69
87
|
end
|
@@ -33,6 +33,7 @@ module GraphqlRails
|
|
33
33
|
groups: groups,
|
34
34
|
hidden_in_groups: hidden_in_groups,
|
35
35
|
**default_value_option,
|
36
|
+
**property_params,
|
36
37
|
**deprecation_reason_params
|
37
38
|
}
|
38
39
|
end
|
@@ -59,6 +60,10 @@ module GraphqlRails
|
|
59
60
|
{ deprecation_reason: deprecation_reason }.compact
|
60
61
|
end
|
61
62
|
|
63
|
+
def property_params
|
64
|
+
{ as: property }.compact
|
65
|
+
end
|
66
|
+
|
62
67
|
def attribute_naming_options
|
63
68
|
options.slice(:input_format)
|
64
69
|
end
|
@@ -94,9 +94,9 @@ module GraphqlRails
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def graphql_type_object?(type_class)
|
97
|
-
return false
|
97
|
+
return false if !type_class.is_a?(Class) && !type_class.is_a?(Module)
|
98
98
|
|
99
|
-
type_class < GraphQL::Schema::Member
|
99
|
+
type_class < GraphQL::Schema::Member::GraphQLTypeNames
|
100
100
|
end
|
101
101
|
|
102
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
|
@@ -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
|
@@ -13,7 +13,7 @@ module GraphqlRails
|
|
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
|
@@ -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)
|
@@ -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
|
@@ -23,6 +23,14 @@ module GraphqlRails
|
|
23
23
|
end
|
24
24
|
end
|
25
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
|
26
34
|
end
|
27
35
|
end
|
28
36
|
end
|
@@ -10,21 +10,35 @@ 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
|
|
@@ -41,6 +55,7 @@ module GraphqlRails
|
|
41
55
|
name: name,
|
42
56
|
type_name: type_name,
|
43
57
|
description: description,
|
58
|
+
implements: implements,
|
44
59
|
parent_class: parent_class
|
45
60
|
)
|
46
61
|
end
|
@@ -53,17 +68,27 @@ module GraphqlRails
|
|
53
68
|
add_attributes_batch(dynamic_attributes)
|
54
69
|
end
|
55
70
|
|
71
|
+
def add_interfaces
|
72
|
+
implements.each do |interface|
|
73
|
+
next if klass.interfaces.include?(interface)
|
74
|
+
|
75
|
+
klass.implements(interface)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
56
79
|
def find_or_build_dynamic_type(attribute)
|
57
80
|
graphql_model = attribute.graphql_model
|
58
|
-
|
81
|
+
return unless graphql_model
|
82
|
+
|
83
|
+
find_or_build_graphql_model_type(graphql_model.graphql)
|
59
84
|
end
|
60
85
|
|
61
|
-
def find_or_build_graphql_model_type(
|
86
|
+
def find_or_build_graphql_model_type(graphql_config)
|
62
87
|
self.class.call(
|
63
|
-
name:
|
64
|
-
description:
|
65
|
-
attributes:
|
66
|
-
type_name:
|
88
|
+
name: graphql_config.name,
|
89
|
+
description: graphql_config.description,
|
90
|
+
attributes: graphql_config.attributes,
|
91
|
+
type_name: graphql_config.type_name
|
67
92
|
)
|
68
93
|
end
|
69
94
|
end
|
@@ -9,12 +9,13 @@ module GraphqlRails
|
|
9
9
|
|
10
10
|
include ::GraphqlRails::Service
|
11
11
|
|
12
|
-
def initialize(name:, type_name:, parent_class:, 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
17
|
@parent_class = parent_class
|
18
|
+
@implements = implements
|
18
19
|
end
|
19
20
|
|
20
21
|
def klass
|
@@ -28,15 +29,17 @@ module GraphqlRails
|
|
28
29
|
private
|
29
30
|
|
30
31
|
attr_accessor :new_class
|
31
|
-
attr_reader :name, :type_name, :description, :parent_class
|
32
|
+
attr_reader :name, :type_name, :description, :parent_class, :implements
|
32
33
|
|
33
34
|
def build_graphql_type_klass
|
34
35
|
graphql_type_name = name
|
35
36
|
graphql_type_description = description
|
37
|
+
interfaces = implements
|
36
38
|
|
37
39
|
graphql_type_klass = Class.new(parent_class) do
|
38
40
|
graphql_name(graphql_type_name)
|
39
41
|
description(graphql_type_description)
|
42
|
+
interfaces.each { |interface| implements(interface) }
|
40
43
|
end
|
41
44
|
|
42
45
|
self.new_class = 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, extras: [:lookahead] }
|
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(
|
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
|
@@ -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,9 +102,13 @@ module GraphqlRails
|
|
94
102
|
|
95
103
|
# controller request object more suitable for testing
|
96
104
|
class Request < GraphqlRails::Controller::Request
|
97
|
-
|
105
|
+
attr_reader :controller, :action_name
|
106
|
+
|
107
|
+
def initialize(params, context, controller: nil, action_name: nil)
|
98
108
|
inputs = params || {}
|
99
109
|
inputs = inputs.merge(lookahead: ::GraphQL::Execution::Lookahead::NullLookahead.new)
|
110
|
+
@controller = controller
|
111
|
+
@action_name = action_name
|
100
112
|
super(nil, inputs, context)
|
101
113
|
end
|
102
114
|
end
|
@@ -104,7 +116,7 @@ module GraphqlRails
|
|
104
116
|
def query(query_name, params: {}, context: {})
|
105
117
|
schema_builder = SingleControllerSchemaBuilder.new(described_class)
|
106
118
|
context_object = FakeContext.new(values: context, schema: schema_builder.call)
|
107
|
-
request = Request.new(params, context_object)
|
119
|
+
request = Request.new(params, context_object, controller: described_class, action_name: query_name)
|
108
120
|
described_class.new(request).call(query_name)
|
109
121
|
|
110
122
|
@response = Response.new(request)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
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:
|
11
|
+
date: 2024-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.
|
19
|
+
version: 2.1.7
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.
|
26
|
+
version: 2.1.7
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,6 +184,7 @@ files:
|
|
184
184
|
- lib/graphql_rails/controller/build_controller_action_resolver.rb
|
185
185
|
- lib/graphql_rails/controller/build_controller_action_resolver/controller_action_resolver.rb
|
186
186
|
- lib/graphql_rails/controller/configuration.rb
|
187
|
+
- lib/graphql_rails/controller/handle_controller_error.rb
|
187
188
|
- lib/graphql_rails/controller/log_controller_action.rb
|
188
189
|
- lib/graphql_rails/controller/request.rb
|
189
190
|
- lib/graphql_rails/controller/request/format_errors.rb
|