graphql 1.10.5 → 1.10.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install_generator.rb +27 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +1 -1
- data/lib/graphql/execution/interpreter.rb +13 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +10 -1
- data/lib/graphql/execution/interpreter/runtime.rb +72 -64
- data/lib/graphql/interface_type.rb +5 -0
- data/lib/graphql/language/nodes.rb +4 -4
- data/lib/graphql/object_type.rb +44 -35
- data/lib/graphql/pagination/connection.rb +24 -4
- data/lib/graphql/pagination/relation_connection.rb +19 -11
- data/lib/graphql/query.rb +28 -1
- data/lib/graphql/query/arguments.rb +2 -1
- data/lib/graphql/query/fingerprint.rb +24 -0
- data/lib/graphql/rake_task.rb +9 -9
- data/lib/graphql/schema.rb +90 -92
- data/lib/graphql/schema/field.rb +33 -13
- data/lib/graphql/schema/field/connection_extension.rb +3 -1
- data/lib/graphql/schema/input_object.rb +14 -2
- data/lib/graphql/schema/interface.rb +10 -0
- data/lib/graphql/schema/loader.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +21 -9
- data/lib/graphql/schema/object.rb +53 -17
- data/lib/graphql/schema/possible_types.rb +9 -4
- data/lib/graphql/schema/warden.rb +48 -7
- data/lib/graphql/types/big_int.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +3 -2
@@ -12,7 +12,7 @@ module GraphQL
|
|
12
12
|
|
13
13
|
def has_previous_page
|
14
14
|
if @has_previous_page.nil?
|
15
|
-
@has_previous_page = if
|
15
|
+
@has_previous_page = if after_offset && after_offset > 0
|
16
16
|
true
|
17
17
|
elsif last
|
18
18
|
# See whether there are any nodes _before_ the current offset.
|
@@ -29,7 +29,7 @@ module GraphQL
|
|
29
29
|
|
30
30
|
def has_next_page
|
31
31
|
if @has_next_page.nil?
|
32
|
-
@has_next_page = if
|
32
|
+
@has_next_page = if before_offset && before_offset > 0
|
33
33
|
true
|
34
34
|
elsif first
|
35
35
|
relation_count(set_limit(sliced_nodes, first + 1)) == first + 1
|
@@ -105,33 +105,41 @@ module GraphQL
|
|
105
105
|
def sliced_nodes
|
106
106
|
@sliced_nodes ||= begin
|
107
107
|
paginated_nodes = items
|
108
|
-
@after_offset = after && offset_from_cursor(after)
|
109
|
-
@before_offset = before && offset_from_cursor(before)
|
110
108
|
|
111
|
-
if
|
109
|
+
if after_offset
|
112
110
|
previous_offset = relation_offset(items) || 0
|
113
|
-
paginated_nodes = set_offset(paginated_nodes, previous_offset +
|
111
|
+
paginated_nodes = set_offset(paginated_nodes, previous_offset + after_offset)
|
114
112
|
end
|
115
113
|
|
116
|
-
if
|
117
|
-
if
|
114
|
+
if before_offset && after_offset
|
115
|
+
if after_offset < before_offset
|
118
116
|
# Get the number of items between the two cursors
|
119
|
-
space_between =
|
117
|
+
space_between = before_offset - after_offset - 1
|
120
118
|
paginated_nodes = set_limit(paginated_nodes, space_between)
|
121
119
|
else
|
122
120
|
# TODO I think this is untested
|
123
121
|
# The cursors overextend one another to an empty set
|
124
122
|
paginated_nodes = null_relation(paginated_nodes)
|
125
123
|
end
|
126
|
-
elsif
|
124
|
+
elsif before_offset
|
127
125
|
# Use limit to cut off the tail of the relation
|
128
|
-
paginated_nodes = set_limit(paginated_nodes,
|
126
|
+
paginated_nodes = set_limit(paginated_nodes, before_offset - 1)
|
129
127
|
end
|
130
128
|
|
131
129
|
paginated_nodes
|
132
130
|
end
|
133
131
|
end
|
134
132
|
|
133
|
+
# @return [Integer, nil]
|
134
|
+
def before_offset
|
135
|
+
@before_offset ||= before && offset_from_cursor(before)
|
136
|
+
end
|
137
|
+
|
138
|
+
# @return [Integer, nil]
|
139
|
+
def after_offset
|
140
|
+
@after_offset ||= after && offset_from_cursor(after)
|
141
|
+
end
|
142
|
+
|
135
143
|
# Apply `first` and `last` to `sliced_nodes`,
|
136
144
|
# returning a new relation
|
137
145
|
def limited_nodes
|
data/lib/graphql/query.rb
CHANGED
@@ -3,6 +3,7 @@ require "graphql/query/arguments"
|
|
3
3
|
require "graphql/query/arguments_cache"
|
4
4
|
require "graphql/query/context"
|
5
5
|
require "graphql/query/executor"
|
6
|
+
require "graphql/query/fingerprint"
|
6
7
|
require "graphql/query/literal_input"
|
7
8
|
require "graphql/query/null_context"
|
8
9
|
require "graphql/query/result"
|
@@ -106,7 +107,7 @@ module GraphQL
|
|
106
107
|
if variables.is_a?(String)
|
107
108
|
raise ArgumentError, "Query variables should be a Hash, not a String. Try JSON.parse to prepare variables."
|
108
109
|
else
|
109
|
-
@provided_variables = variables
|
110
|
+
@provided_variables = variables || {}
|
110
111
|
end
|
111
112
|
|
112
113
|
@query_string = query_string || query
|
@@ -265,6 +266,32 @@ module GraphQL
|
|
265
266
|
}
|
266
267
|
end
|
267
268
|
|
269
|
+
# This contains a few components:
|
270
|
+
#
|
271
|
+
# - The selected operation name (or `anonymous`)
|
272
|
+
# - The fingerprint of the query string
|
273
|
+
# - The number of given variables (for readability)
|
274
|
+
# - The fingerprint of the given variables
|
275
|
+
#
|
276
|
+
# This fingerprint can be used to track runs of the same operation-variables combination over time.
|
277
|
+
#
|
278
|
+
# @see operation_fingerprint
|
279
|
+
# @see variables_fingerprint
|
280
|
+
# @return [String] An opaque hash identifying this operation-variables combination
|
281
|
+
def fingerprint
|
282
|
+
@fingerprint ||= "#{operation_fingerprint}/#{variables_fingerprint}"
|
283
|
+
end
|
284
|
+
|
285
|
+
# @return [String] An opaque hash for identifying this query's given query string and selected operation
|
286
|
+
def operation_fingerprint
|
287
|
+
@operation_fingerprint ||= "#{selected_operation_name || "anonymous"}/#{Fingerprint.generate(query_string)}"
|
288
|
+
end
|
289
|
+
|
290
|
+
# @return [String] An opaque hash for identifying this query's given a variable values (not including defaults)
|
291
|
+
def variables_fingerprint
|
292
|
+
@variables_fingerprint ||= "#{provided_variables.size}/#{Fingerprint.generate(provided_variables.to_json)}"
|
293
|
+
end
|
294
|
+
|
268
295
|
def validation_pipeline
|
269
296
|
with_prepared_ast { @validation_pipeline }
|
270
297
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Query
|
5
|
+
# @api private
|
6
|
+
# @see Query#query_fingerprint
|
7
|
+
# @see Query#variables_fingerprint
|
8
|
+
# @see Query#fingerprint
|
9
|
+
module Fingerprint
|
10
|
+
# Make an obfuscated hash of the given string (either a query string or variables JSON)
|
11
|
+
# @param string [String]
|
12
|
+
# @return [String] A normalized, opaque hash
|
13
|
+
def self.generate(input_str)
|
14
|
+
# Implemented to be:
|
15
|
+
# - Short (and uniform) length
|
16
|
+
# - Stable
|
17
|
+
# - Irreversibly Opaque (don't want to leak variable values)
|
18
|
+
# - URL-friendly
|
19
|
+
bytes = Digest::SHA256.digest(input_str)
|
20
|
+
Base64.urlsafe_encode64(bytes)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/graphql/rake_task.rb
CHANGED
@@ -76,15 +76,7 @@ module GraphQL
|
|
76
76
|
# Set the parameters of this task by passing keyword arguments
|
77
77
|
# or assigning attributes inside the block
|
78
78
|
def initialize(options = {})
|
79
|
-
|
80
|
-
[:environment]
|
81
|
-
else
|
82
|
-
[]
|
83
|
-
end
|
84
|
-
|
85
|
-
all_options = DEFAULT_OPTIONS
|
86
|
-
.merge(dependencies: default_dependencies)
|
87
|
-
.merge(options)
|
79
|
+
all_options = DEFAULT_OPTIONS.merge(options)
|
88
80
|
all_options.each do |k, v|
|
89
81
|
self.public_send("#{k}=", v)
|
90
82
|
end
|
@@ -117,18 +109,26 @@ module GraphQL
|
|
117
109
|
File.join(@directory, @json_outfile)
|
118
110
|
end
|
119
111
|
|
112
|
+
def load_rails_environment_if_defined
|
113
|
+
if Rake::Task.task_defined?('environment')
|
114
|
+
Rake::Task['environment'].invoke
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
120
118
|
# Use the Rake DSL to add tasks
|
121
119
|
def define_task
|
122
120
|
namespace(@namespace) do
|
123
121
|
namespace("schema") do
|
124
122
|
desc("Dump the schema to IDL in #{idl_path}")
|
125
123
|
task :idl => @dependencies do
|
124
|
+
load_rails_environment_if_defined
|
126
125
|
write_outfile(:to_definition, idl_path)
|
127
126
|
puts "Schema IDL dumped into #{idl_path}"
|
128
127
|
end
|
129
128
|
|
130
129
|
desc("Dump the schema to JSON in #{json_path}")
|
131
130
|
task :json => @dependencies do
|
131
|
+
load_rails_environment_if_defined
|
132
132
|
write_outfile(:to_json, json_path)
|
133
133
|
puts "Schema JSON dumped into #{json_path}"
|
134
134
|
end
|
data/lib/graphql/schema.rb
CHANGED
@@ -96,6 +96,67 @@ module GraphQL
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
+
module LazyHandlingMethods
|
100
|
+
# Call the given block at the right time, either:
|
101
|
+
# - Right away, if `value` is not registered with `lazy_resolve`
|
102
|
+
# - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
|
103
|
+
# @api private
|
104
|
+
def after_lazy(value)
|
105
|
+
if lazy?(value)
|
106
|
+
GraphQL::Execution::Lazy.new do
|
107
|
+
result = sync_lazy(value)
|
108
|
+
# The returned result might also be lazy, so check it, too
|
109
|
+
after_lazy(result) do |final_result|
|
110
|
+
yield(final_result) if block_given?
|
111
|
+
end
|
112
|
+
end
|
113
|
+
else
|
114
|
+
yield(value) if block_given?
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Override this method to handle lazy objects in a custom way.
|
119
|
+
# @param value [Object] an instance of a class registered with {.lazy_resolve}
|
120
|
+
# @return [Object] A GraphQL-ready (non-lazy) object
|
121
|
+
# @api private
|
122
|
+
def sync_lazy(value)
|
123
|
+
lazy_method = lazy_method_name(value)
|
124
|
+
if lazy_method
|
125
|
+
synced_value = value.public_send(lazy_method)
|
126
|
+
sync_lazy(synced_value)
|
127
|
+
else
|
128
|
+
value
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
|
133
|
+
def lazy_method_name(obj)
|
134
|
+
lazy_methods.get(obj)
|
135
|
+
end
|
136
|
+
|
137
|
+
# @return [Boolean] True if this object should be lazily resolved
|
138
|
+
def lazy?(obj)
|
139
|
+
!!lazy_method_name(obj)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Return a lazy if any of `maybe_lazies` are lazy,
|
143
|
+
# otherwise, call the block eagerly and return the result.
|
144
|
+
# @param maybe_lazies [Array]
|
145
|
+
# @api private
|
146
|
+
def after_any_lazies(maybe_lazies)
|
147
|
+
if maybe_lazies.any? { |l| lazy?(l) }
|
148
|
+
GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
|
149
|
+
yield
|
150
|
+
end
|
151
|
+
else
|
152
|
+
yield
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
include LazyHandlingMethods
|
158
|
+
extend LazyHandlingMethods
|
159
|
+
|
99
160
|
accepts_definitions \
|
100
161
|
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
101
162
|
:max_depth, :max_complexity, :default_max_page_size,
|
@@ -740,16 +801,6 @@ module GraphQL
|
|
740
801
|
# Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
|
741
802
|
class InvalidDocumentError < Error; end;
|
742
803
|
|
743
|
-
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
|
744
|
-
def lazy_method_name(obj)
|
745
|
-
@lazy_methods.get(obj)
|
746
|
-
end
|
747
|
-
|
748
|
-
# @return [Boolean] True if this object should be lazily resolved
|
749
|
-
def lazy?(obj)
|
750
|
-
!!lazy_method_name(obj)
|
751
|
-
end
|
752
|
-
|
753
804
|
# Return the GraphQL IDL for the schema
|
754
805
|
# @param context [Hash]
|
755
806
|
# @param only [<#call(member, ctx)>]
|
@@ -1582,48 +1633,6 @@ module GraphQL
|
|
1582
1633
|
end
|
1583
1634
|
end
|
1584
1635
|
|
1585
|
-
# Call the given block at the right time, either:
|
1586
|
-
# - Right away, if `value` is not registered with `lazy_resolve`
|
1587
|
-
# - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
|
1588
|
-
# @api private
|
1589
|
-
def after_lazy(value)
|
1590
|
-
if lazy?(value)
|
1591
|
-
GraphQL::Execution::Lazy.new do
|
1592
|
-
result = sync_lazy(value)
|
1593
|
-
# The returned result might also be lazy, so check it, too
|
1594
|
-
after_lazy(result) do |final_result|
|
1595
|
-
yield(final_result) if block_given?
|
1596
|
-
end
|
1597
|
-
end
|
1598
|
-
else
|
1599
|
-
yield(value) if block_given?
|
1600
|
-
end
|
1601
|
-
end
|
1602
|
-
|
1603
|
-
# Override this method to handle lazy objects in a custom way.
|
1604
|
-
# @param value [Object] an instance of a class registered with {.lazy_resolve}
|
1605
|
-
# @param ctx [GraphQL::Query::Context] the context for this query
|
1606
|
-
# @return [Object] A GraphQL-ready (non-lazy) object
|
1607
|
-
def sync_lazy(value)
|
1608
|
-
lazy_method = lazy_method_name(value)
|
1609
|
-
if lazy_method
|
1610
|
-
synced_value = value.public_send(lazy_method)
|
1611
|
-
sync_lazy(synced_value)
|
1612
|
-
else
|
1613
|
-
value
|
1614
|
-
end
|
1615
|
-
end
|
1616
|
-
|
1617
|
-
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
|
1618
|
-
def lazy_method_name(obj)
|
1619
|
-
lazy_methods.get(obj)
|
1620
|
-
end
|
1621
|
-
|
1622
|
-
# @return [Boolean] True if this object should be lazily resolved
|
1623
|
-
def lazy?(obj)
|
1624
|
-
!!lazy_method_name(obj)
|
1625
|
-
end
|
1626
|
-
|
1627
1636
|
private
|
1628
1637
|
|
1629
1638
|
def lazy_methods
|
@@ -1756,16 +1765,24 @@ module GraphQL
|
|
1756
1765
|
}
|
1757
1766
|
own_possible_types[owner.graphql_name] = owner.possible_types
|
1758
1767
|
elsif type.kind.interface? && owner.kind.object?
|
1759
|
-
new_interfaces =
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1768
|
+
new_interfaces = []
|
1769
|
+
owner.interfaces.each do |int_t|
|
1770
|
+
if int_t.is_a?(String) && int_t == type.graphql_name
|
1771
|
+
new_interfaces << type
|
1772
|
+
elsif int_t.is_a?(LateBoundType) && int_t.graphql_name == type.graphql_name
|
1773
|
+
new_interfaces << type
|
1764
1774
|
else
|
1765
|
-
t
|
1775
|
+
# Don't re-add proper interface definitions,
|
1776
|
+
# they were probably already added, maybe with options.
|
1766
1777
|
end
|
1767
1778
|
end
|
1768
1779
|
owner.implements(*new_interfaces)
|
1780
|
+
new_interfaces.each do |int|
|
1781
|
+
pt = own_possible_types[int.graphql_name] ||= []
|
1782
|
+
if !pt.include?(owner)
|
1783
|
+
pt << owner
|
1784
|
+
end
|
1785
|
+
end
|
1769
1786
|
end
|
1770
1787
|
|
1771
1788
|
when nil
|
@@ -1864,46 +1881,27 @@ module GraphQL
|
|
1864
1881
|
end
|
1865
1882
|
if type.kind.object?
|
1866
1883
|
own_possible_types[type.graphql_name] = [type]
|
1867
|
-
type.
|
1868
|
-
|
1869
|
-
|
1870
|
-
|
1884
|
+
type.interface_type_memberships.each do |interface_type_membership|
|
1885
|
+
case interface_type_membership
|
1886
|
+
when Schema::TypeMembership
|
1887
|
+
interface_type = interface_type_membership.abstract_type
|
1888
|
+
# We can get these now; we'll have to get late-bound types later
|
1889
|
+
if interface_type.is_a?(Module)
|
1890
|
+
implementers = own_possible_types[interface_type.graphql_name] ||= []
|
1891
|
+
implementers << type
|
1892
|
+
end
|
1893
|
+
when String, Schema::LateBoundType
|
1894
|
+
interface_type = interface_type_membership
|
1895
|
+
else
|
1896
|
+
raise ArgumentError, "Invariant: unexpected type membership for #{type.graphql_name}: #{interface_type_membership.class} (#{interface_type_membership.inspect})"
|
1897
|
+
end
|
1898
|
+
add_type(interface_type, owner: type, late_types: late_types, path: path + ["implements"])
|
1871
1899
|
end
|
1872
1900
|
end
|
1873
1901
|
end
|
1874
1902
|
end
|
1875
1903
|
end
|
1876
1904
|
|
1877
|
-
# Call the given block at the right time, either:
|
1878
|
-
# - Right away, if `value` is not registered with `lazy_resolve`
|
1879
|
-
# - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
|
1880
|
-
# @api private
|
1881
|
-
def after_lazy(value)
|
1882
|
-
if lazy?(value)
|
1883
|
-
GraphQL::Execution::Lazy.new do
|
1884
|
-
result = sync_lazy(value)
|
1885
|
-
# The returned result might also be lazy, so check it, too
|
1886
|
-
after_lazy(result) do |final_result|
|
1887
|
-
yield(final_result) if block_given?
|
1888
|
-
end
|
1889
|
-
end
|
1890
|
-
else
|
1891
|
-
yield(value) if block_given?
|
1892
|
-
end
|
1893
|
-
end
|
1894
|
-
|
1895
|
-
# @see Schema.sync_lazy for a hook to override
|
1896
|
-
# @api private
|
1897
|
-
def sync_lazy(value)
|
1898
|
-
lazy_method = lazy_method_name(value)
|
1899
|
-
if lazy_method
|
1900
|
-
synced_value = value.public_send(lazy_method)
|
1901
|
-
sync_lazy(synced_value)
|
1902
|
-
else
|
1903
|
-
value
|
1904
|
-
end
|
1905
|
-
end
|
1906
|
-
|
1907
1905
|
protected
|
1908
1906
|
|
1909
1907
|
def rescues?
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -173,7 +173,7 @@ module GraphQL
|
|
173
173
|
# @param resolver_method [Symbol] The method on the type to call to resolve this field (defaults to `name`)
|
174
174
|
# @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
|
175
175
|
# @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
|
176
|
-
# @param max_page_size [Integer] For connections, the maximum number of items to return from this field
|
176
|
+
# @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
|
177
177
|
# @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
|
178
178
|
# @param resolve [<#call(obj, args, ctx)>] **deprecated** for compatibility with <1.8.0
|
179
179
|
# @param field [GraphQL::Field, GraphQL::Schema::Field] **deprecated** for compatibility with <1.8.0
|
@@ -188,7 +188,7 @@ module GraphQL
|
|
188
188
|
# @param trace [Boolean] If true, a {GraphQL::Tracing} tracer will measure this scalar field
|
189
189
|
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
190
190
|
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
191
|
-
def initialize(type: nil, name: nil, owner: nil, null: nil, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size:
|
191
|
+
def initialize(type: nil, name: nil, owner: nil, null: nil, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, ast_node: nil, extras: [], extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, arguments: EMPTY_HASH, &definition_block)
|
192
192
|
if name.nil?
|
193
193
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
194
194
|
end
|
@@ -242,7 +242,8 @@ module GraphQL
|
|
242
242
|
@return_type_expr = type
|
243
243
|
@return_type_null = null
|
244
244
|
@connection = connection
|
245
|
-
@
|
245
|
+
@has_max_page_size = max_page_size != :not_given
|
246
|
+
@max_page_size = max_page_size == :not_given ? nil : max_page_size
|
246
247
|
@introspection = introspection
|
247
248
|
@extras = extras
|
248
249
|
@resolver_class = resolver_class
|
@@ -381,7 +382,12 @@ module GraphQL
|
|
381
382
|
end
|
382
383
|
end
|
383
384
|
|
384
|
-
# @return [
|
385
|
+
# @return [Boolean] True if this field's {#max_page_size} should override the schema default.
|
386
|
+
def has_max_page_size?
|
387
|
+
@has_max_page_size
|
388
|
+
end
|
389
|
+
|
390
|
+
# @return [Integer, nil] Applied to connections if {#has_max_page_size?}
|
385
391
|
attr_reader :max_page_size
|
386
392
|
|
387
393
|
# @return [GraphQL::Field]
|
@@ -646,22 +652,34 @@ module GraphQL
|
|
646
652
|
if graphql_args.any? || @extras.any?
|
647
653
|
# Splat the GraphQL::Arguments to Ruby keyword arguments
|
648
654
|
ruby_kwargs = graphql_args.to_kwargs
|
655
|
+
maybe_lazies = []
|
649
656
|
# Apply any `prepare` methods. Not great code organization, can this go somewhere better?
|
650
657
|
arguments.each do |name, arg_defn|
|
651
658
|
ruby_kwargs_key = arg_defn.keyword
|
652
659
|
|
653
|
-
|
654
|
-
|
660
|
+
if ruby_kwargs.key?(ruby_kwargs_key)
|
661
|
+
loads = arg_defn.loads
|
655
662
|
value = ruby_kwargs[ruby_kwargs_key]
|
656
|
-
|
657
|
-
|
663
|
+
loaded_value = if loads && !arg_defn.from_resolver?
|
664
|
+
if arg_defn.type.list?
|
665
|
+
loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, field_ctx.query.context) }
|
666
|
+
maybe_lazies.concat(loaded_values)
|
667
|
+
else
|
668
|
+
load_application_object(arg_defn, loads, value, field_ctx.query.context)
|
669
|
+
end
|
658
670
|
else
|
659
|
-
|
671
|
+
value
|
660
672
|
end
|
661
|
-
end
|
662
673
|
|
663
|
-
|
664
|
-
|
674
|
+
maybe_lazies << field_ctx.schema.after_lazy(loaded_value) do |loaded_value|
|
675
|
+
prepared_value = if arg_defn.prepare
|
676
|
+
arg_defn.prepare_value(obj, loaded_value)
|
677
|
+
else
|
678
|
+
loaded_value
|
679
|
+
end
|
680
|
+
|
681
|
+
ruby_kwargs[ruby_kwargs_key] = prepared_value
|
682
|
+
end
|
665
683
|
end
|
666
684
|
end
|
667
685
|
|
@@ -669,7 +687,9 @@ module GraphQL
|
|
669
687
|
ruby_kwargs[extra_arg] = fetch_extra(extra_arg, field_ctx)
|
670
688
|
end
|
671
689
|
|
672
|
-
|
690
|
+
field_ctx.schema.after_any_lazies(maybe_lazies) do
|
691
|
+
ruby_kwargs
|
692
|
+
end
|
673
693
|
else
|
674
694
|
NO_ARGS
|
675
695
|
end
|