You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: guides/execution/migration.md
+14Lines changed: 14 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -145,6 +145,20 @@ render json: result.to_h
145
145
146
146
Performance improvements in batching execution come at the cost of removing support for many "nice-to-have" features in GraphQL-Ruby by default. Those features are addressed here.
147
147
148
+
### Implicit Field Resolution
149
+
150
+
The _default_, _implicit_ field resolution behavior has changed. Previously, when a field didn't have a specified method or hash key, GraphQL-Ruby would try a combination of `object.public_send(...)` and `object[...]` to resolve it. In `Execution::Next`, GraphQL-Ruby tries `object.public_send(field_sym)` unless another configuration is provided. This removes a lot of overhead from field execution.
151
+
152
+
Consider a field like this:
153
+
154
+
```ruby
155
+
field :title, String
156
+
```
157
+
158
+
Previously, GraphQL-Ruby would check `type_object.respond_to?(:title)`, `object.respond_to?(:title)`, `object.is_a?(Hash)`. `object.key?(:title)` and `object.key?("title")`.
159
+
160
+
Now, GraphQL-Ruby simply calls `object.title` and allows the `NoMethodError` to bubble up if one is raised.
161
+
148
162
### Query Analyzers, including complexity 🌕
149
163
150
164
Support is identical; this runs before execution using the exact same code.
Copy file name to clipboardExpand all lines: guides/execution/next.md
+96-59Lines changed: 96 additions & 59 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -44,89 +44,125 @@ See {% internal_link "compatibility notes", "/execution/migration#compatibility-
44
44
45
45
## Field configurations
46
46
47
-
The new runtime engine supports several field resolution configurations out of the box:
47
+
The new runtime engine supports several field resolution configurations out of the box.
48
48
49
-
-__Method calls__: fields that call `object.#{field_name}`. This is the default, and the method name can be overridden with `method: ...`:
49
+
### Method calls (default, `method:`)
50
50
51
-
```ruby
52
-
field :title, String# calls object.title
53
-
field :title, String, method::get_title_somehow# calls object.get_title_somehow
54
-
```
55
-
-__Hashkeys__: fields that call `object[hash_key]`, configured with `hash_key: ...`.
51
+
Fields that call `object.#{field_name}`. This is the default, and the method name can be overridden with `method: ...`:
56
52
53
+
```ruby
54
+
field :title, String# calls object.title
55
+
field :title, String, method::get_title_somehow# calls object.get_title_somehow
56
+
```
57
57
58
-
```ruby
59
-
field :title, String, hash_key: :title # calls object[:title]
60
-
field :title, String, hash_key: "title" # calls object["title"]
61
-
```
58
+
### Hash keys (`hash_key:`)
62
59
63
-
(Note:new execution doesn't "fall back" to hash key lookups, and it doesn't try strings whenSymbols are given. The existing runtime engine does that...)
60
+
Fields that call `object[hash_key]`, configured with `hash_key: ...`.
64
61
65
-
-__Batchresolvers__: fields that use a _class method_ to map parent objects to field results, configured with `resolve_batch:`:
62
+
```ruby
63
+
field :title, String, hash_key::title# calls object[:title]
64
+
field :title, String, hash_key:"title"# calls object["title"]
(Note: new execution doesn't "fall back" to hash key lookups, and it doesn't try strings when Symbols are given. The existing runtime engine does that...)
71
68
72
-
def self.titles(objects, context, language:)
73
-
# This is equivalent to plain `field :title, ...`, but for example:
74
-
objects.map { |obj| obj.title(language:) }
75
-
end
76
-
```
69
+
### Per-object (`resolve_each:`)
77
70
78
-
This is especially useful when batching Dataloadercalls:
71
+
These fields use a _class method_ to produce a result for each parent object, configured with `resolve_each:`.
# Use `.load_all(ids)` to fetch all in a single round-trip
85
-
def self.posts(objects, context)
86
-
# TODO: add a shorthand for this in GraphQL-Ruby
87
-
context.dataloader
88
-
.with(GraphQL::Dataloader::ActiveRecordSource)
89
-
.load_all(objects.map(&:post_id))
90
-
end
91
-
end
92
-
```
78
+
defself.title(object, context, language:)
79
+
# Assuming this makes no database lookups or other external service calls:
80
+
object.localization.get(:title, language:)
81
+
end
82
+
```
93
83
94
-
-__Eachresolvers__: fields that use a _class method_ to produce a result for each parent object, configured with `resolve_each:`. This is similar to `resolve_batch:`, except you never receive the whole list of `objects`:
84
+
Under the hood, GraphQL-Ruby calls `objects.map { ... }`, calling this class method.
‼️ __Don't use this__ if your logic calls external services or databases (including with Dataloader). If you do, your I/O will be sequential instead of batched. Use `resolve_batch:` or `resolve_static:` instead, see below.
100
87
101
-
def self.title(object, context, language:)
102
-
object.title(language:)
103
-
end
104
-
```
88
+
### Global (`resolve_static:`)
105
89
106
-
(Under the hood, GraphQL-Ruby calls `objects.map { ... }`, calling this class method.)
90
+
Fields that use a _class method_ to produce a single result shared by all objects, configured with `resolve_static:`. The method does _not_ receive any `object`, only `context`:
107
91
108
-
-__Staticresolvers__: fields that use a _class method_ to produce a single result shared by all objects, configured with `resolve_static:`. The method does _not_ receive any `object`, only `context`:
92
+
```ruby
93
+
field :posts_count, Integer, resolve_static::count_all_postsdo
This is a high-performance option for when you need to do I/O to generate results. By working with a batch of objects, you can greatly reduce the framework overhead in preparing a result.
111
+
112
+
These fields use a _class method_ to map parent objects to field results, configured with `resolve_batch:`:
# Assuming this makes no database lookups or other external service calls:
156
+
object.localization.get(:title, language:)
157
+
end
158
+
```
159
+
160
+
Under the hood, GraphQL-Ruby calls `objects.map { ... }`, calling this instance method.
125
161
126
162
127
163
### `true` shorthand
128
164
129
-
There is also a `true`shorthand:when one of the `resolve_...:` configurations is passed as `true` (ie, `resolve_batch: true`, `resolve_each: true`, or`resolve_static: true`), then the Symbol field name is used as the class method. For example:
165
+
There is also a `true` shorthand: when one of the `resolve_...:` configurations is passed as `true` (ie, `resolve_batch: true`, `resolve_each: true`, `resolve_static: true`, or `resolve_legacy_instance_method: true`), then the Symbol field name is used as the class method. For example:
130
166
131
167
```ruby
132
168
field :posts_count, Integer, resolve_static:true
@@ -136,6 +172,7 @@ def self.posts_count(context)
136
172
end
137
173
```
138
174
175
+
139
176
## Migration
140
177
141
178
Read about migrating in the {% internal_link "Migration Doc", "/execution/migration" %}.
0 commit comments