graphql 1.5.5 → 1.5.6

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +1 -2
  3. data/lib/graphql/analysis/query_complexity.rb +0 -1
  4. data/lib/graphql/argument.rb +43 -3
  5. data/lib/graphql/base_type.rb +50 -7
  6. data/lib/graphql/boolean_type.rb +2 -2
  7. data/lib/graphql/compatibility/execution_specification.rb +1 -1
  8. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
  9. data/lib/graphql/compatibility/lazy_execution_specification.rb +1 -1
  10. data/lib/graphql/enum_type.rb +35 -27
  11. data/lib/graphql/execution/execute.rb +3 -5
  12. data/lib/graphql/execution/lazy/lazy_method_map.rb +2 -2
  13. data/lib/graphql/float_type.rb +2 -2
  14. data/lib/graphql/function.rb +5 -0
  15. data/lib/graphql/id_type.rb +2 -2
  16. data/lib/graphql/input_object_type.rb +46 -36
  17. data/lib/graphql/int_type.rb +2 -2
  18. data/lib/graphql/introspection/input_value_type.rb +1 -1
  19. data/lib/graphql/list_type.rb +17 -17
  20. data/lib/graphql/non_null_type.rb +6 -11
  21. data/lib/graphql/query.rb +2 -2
  22. data/lib/graphql/query/literal_input.rb +15 -8
  23. data/lib/graphql/query/null_context.rb +29 -0
  24. data/lib/graphql/query/serial_execution/value_resolution.rb +2 -4
  25. data/lib/graphql/query/variables.rb +9 -7
  26. data/lib/graphql/relay/mutation.rb +6 -7
  27. data/lib/graphql/scalar_type.rb +54 -19
  28. data/lib/graphql/schema.rb +21 -5
  29. data/lib/graphql/schema/build_from_definition.rb +3 -1
  30. data/lib/graphql/schema/catchall_middleware.rb +1 -1
  31. data/lib/graphql/schema/default_type_error.rb +1 -1
  32. data/lib/graphql/schema/loader.rb +2 -2
  33. data/lib/graphql/schema/printer.rb +1 -1
  34. data/lib/graphql/schema/validation.rb +1 -2
  35. data/lib/graphql/static_validation/arguments_validator.rb +1 -1
  36. data/lib/graphql/static_validation/literal_validator.rb +5 -4
  37. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +1 -1
  38. data/lib/graphql/static_validation/validation_context.rb +1 -1
  39. data/lib/graphql/string_encoding_error.rb +10 -0
  40. data/lib/graphql/string_type.rb +8 -3
  41. data/lib/graphql/version.rb +1 -1
  42. data/spec/graphql/argument_spec.rb +13 -0
  43. data/spec/graphql/base_type_spec.rb +1 -1
  44. data/spec/graphql/boolean_type_spec.rb +1 -1
  45. data/spec/graphql/enum_type_spec.rb +11 -11
  46. data/spec/graphql/field_spec.rb +1 -1
  47. data/spec/graphql/float_type_spec.rb +4 -4
  48. data/spec/graphql/function_spec.rb +5 -4
  49. data/spec/graphql/input_object_type_spec.rb +28 -20
  50. data/spec/graphql/int_type_spec.rb +4 -4
  51. data/spec/graphql/language/lexer_spec.rb +0 -1
  52. data/spec/graphql/list_type_spec.rb +3 -3
  53. data/spec/graphql/query/literal_input_spec.rb +51 -0
  54. data/spec/graphql/query/variables_spec.rb +8 -4
  55. data/spec/graphql/relay/array_connection_spec.rb +1 -1
  56. data/spec/graphql/relay/page_info_spec.rb +1 -1
  57. data/spec/graphql/relay/relation_connection_spec.rb +3 -3
  58. data/spec/graphql/scalar_type_spec.rb +8 -8
  59. data/spec/graphql/schema/build_from_definition_spec.rb +2 -2
  60. data/spec/graphql/schema/loader_spec.rb +4 -4
  61. data/spec/graphql/string_type_spec.rb +33 -6
  62. data/spec/spec_helper.rb +0 -11
  63. data/spec/support/dummy/schema.rb +1 -1
  64. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef472807dc31f5d5bc215491e5c4a512d853b517
4
- data.tar.gz: 151d4556ac7c07a270e37e40a71616dfad89129b
3
+ metadata.gz: 8fd00bd7b6d3c884c97818e792423683197e2f45
4
+ data.tar.gz: 731475b235eb76d4ea0e574e734d8adba1188c96
5
5
  SHA512:
6
- metadata.gz: 825fdd6d9aac63cf8904e1a52be462499286063ccab8799497affabf52d1a0b8b2afe090e5fef84a564c087803ca4b4b38d4dc7fa898e145047e749aa1d0e12c
7
- data.tar.gz: 43c0d734ac9014bd7df9f9e26e70052e62f2ae0d7a84b59642622e2786ffd806fbc076638411ce4621b2dd355c7479ac05c7e9fed8993701126611c8ebe428d6
6
+ metadata.gz: 54fc7fd2ac112ba5be3d405d256dfe81d3dfa58c688820f406fbe97671245b7395076484915b1c67cb074a948304c015af52f5888fa1670eee88bc68f7dab779
7
+ data.tar.gz: d4fc22d899a6ea6fd5bbd3895c0f5c5837956a3264b0badbfc6f09237a07ac02fa489b3f114f62c3247067157a4e85051f48cee4d301be89d5792d48893d2af2
@@ -82,12 +82,11 @@ require "graphql/schema"
82
82
  require "graphql/schema/loader"
83
83
  require "graphql/schema/printer"
84
84
 
85
- # Order does not matter for these:
86
-
87
85
  require "graphql/analysis_error"
88
86
  require "graphql/runtime_type_error"
89
87
  require "graphql/invalid_null_error"
90
88
  require "graphql/unresolved_type_error"
89
+ require "graphql/string_encoding_error"
91
90
  require "graphql/query"
92
91
  require "graphql/internal_representation"
93
92
  require "graphql/static_validation"
@@ -53,7 +53,6 @@ module GraphQL
53
53
  # Get a complexity value for a field,
54
54
  # by getting the number or calling its proc
55
55
  def get_complexity(irep_node, query, child_complexity)
56
- type_defn = irep_node.owner_type
57
56
  field_defn = irep_node.definition
58
57
  defined_complexity = field_defn.complexity
59
58
  case defined_complexity
@@ -14,13 +14,40 @@ module GraphQL
14
14
  # GraphQL::InputObjectType.define do
15
15
  # argument :newName, !types.String
16
16
  # end
17
+ #
18
+ # @example defining an argument with a `prepare` function
19
+ # GraphQL::Field.define do
20
+ # argument :userId, types.ID, prepare: ->(userId) do
21
+ # User.find_by(id: userId)
22
+ # end
23
+ # end
24
+ #
25
+ # @example returning an {ExecutionError} from a `prepare` function
26
+ # GraphQL::Field.define do
27
+ # argument :date do
28
+ # type !types.String
29
+ # prepare ->(date) do
30
+ # return GraphQL::ExecutionError.new("Invalid date format") unless DateValidator.valid?(date)
31
+ # Time.zone.parse(date)
32
+ # end
33
+ # end
34
+ # end
17
35
 
18
36
  class Argument
19
37
  include GraphQL::Define::InstanceDefinable
20
- accepts_definitions :name, :type, :description, :default_value, :as
38
+ accepts_definitions :name, :type, :description, :default_value, :as, :prepare
21
39
  attr_accessor :type, :description, :default_value, :name, :as
22
40
 
23
- ensure_defined(:name, :description, :default_value, :type=, :type, :as, :expose_as)
41
+ ensure_defined(:name, :description, :default_value, :type=, :type, :as, :expose_as, :prepare)
42
+
43
+ # @api private
44
+ module DefaultPrepare
45
+ def self.call(value); value; end
46
+ end
47
+
48
+ def initialize
49
+ @prepare_proc = DefaultPrepare
50
+ end
24
51
 
25
52
  def initialize_copy(other)
26
53
  @expose_as = nil
@@ -54,9 +81,21 @@ module GraphQL
54
81
  @expose_as ||= (@as || @name).to_s
55
82
  end
56
83
 
84
+ # @param value
85
+ # @return [Object] The prepared `value` for this argument or `value` itself if no `prepare` function exists.
86
+ def prepare(value)
87
+ @prepare_proc.call(value)
88
+ end
89
+
90
+ # Assign a `prepare` function to prepare this argument's value before `resolve` functions are called.
91
+ # @param prepare_proc [Proc]
92
+ def prepare=(prepare_proc)
93
+ @prepare_proc = prepare_proc
94
+ end
95
+
57
96
  NO_DEFAULT_VALUE = Object.new
58
97
  # @api private
59
- def self.from_dsl(name, type = nil, description = nil, default_value: NO_DEFAULT_VALUE, as: nil, &block)
98
+ def self.from_dsl(name, type = nil, description = nil, default_value: NO_DEFAULT_VALUE, as: nil, prepare: DefaultPrepare, &block)
60
99
  argument = if block_given?
61
100
  GraphQL::Argument.define(&block)
62
101
  else
@@ -70,6 +109,7 @@ module GraphQL
70
109
  argument.default_value = default_value
71
110
  end
72
111
  argument.as = as
112
+ argument.prepare = prepare
73
113
 
74
114
 
75
115
  argument
@@ -97,21 +97,58 @@ module GraphQL
97
97
 
98
98
  alias :inspect :to_s
99
99
 
100
- def valid_input?(value, warden)
101
- validate_input(value, warden).valid?
100
+ def valid_isolated_input?(value)
101
+ valid_input?(value, GraphQL::Query::NullContext)
102
102
  end
103
103
 
104
- def validate_input(value, warden)
104
+ def validate_isolated_input(value)
105
+ validate_input(value, GraphQL::Query::NullContext)
106
+ end
107
+
108
+ def coerce_isolated_input(value)
109
+ coerce_input(value, GraphQL::Query::NullContext)
110
+ end
111
+
112
+ def coerce_isolated_result(value)
113
+ coerce_result(value, GraphQL::Query::NullContext)
114
+ end
115
+
116
+ def valid_input?(value, ctx = nil)
117
+ if ctx.nil?
118
+ warn_deprecated_coerce("valid_isolated_input?")
119
+ ctx = GraphQL::Query::NullContext
120
+ end
121
+
122
+ validate_input(value, ctx).valid?
123
+ end
124
+
125
+ def validate_input(value, ctx = nil)
126
+ if ctx.nil?
127
+ warn_deprecated_coerce("validate_isolated_input")
128
+ ctx = GraphQL::Query::NullContext
129
+ end
130
+
105
131
  if value.nil?
106
132
  GraphQL::Query::InputValidationResult.new
107
133
  else
108
- validate_non_null_input(value, warden)
134
+ validate_non_null_input(value, ctx)
135
+ end
136
+ end
137
+
138
+ def coerce_input(value, ctx = nil)
139
+ if value.nil?
140
+ nil
141
+ else
142
+ if ctx.nil?
143
+ warn_deprecated_coerce("coerce_isolated_input")
144
+ ctx = GraphQL::Query::NullContext
145
+ end
146
+ coerce_non_null_input(value, ctx)
109
147
  end
110
148
  end
111
149
 
112
- def coerce_input(value)
113
- return nil if value.nil?
114
- coerce_non_null_input(value)
150
+ def coerce_result(value, ctx)
151
+ raise NotImplementedError
115
152
  end
116
153
 
117
154
  # Types with fields may override this
@@ -168,5 +205,11 @@ module GraphQL
168
205
  printer ||= GraphQL::Schema::Printer.new(schema, **args)
169
206
  printer.print_type(self)
170
207
  end
208
+
209
+ private
210
+
211
+ def warn_deprecated_coerce(alt_method_name)
212
+ warn("Coercing without a context is deprecated; use `#{alt_method_name}` if you don't want context-awareness")
213
+ end
171
214
  end
172
215
  end
@@ -3,7 +3,7 @@ GraphQL::BOOLEAN_TYPE = GraphQL::ScalarType.define do
3
3
  name "Boolean"
4
4
  description "Represents `true` or `false` values."
5
5
 
6
- coerce_input ->(value) { (value == true || value == false) ? value : nil }
7
- coerce_result ->(value) { !!value }
6
+ coerce_input ->(value, _ctx) { (value == true || value == false) ? value : nil }
7
+ coerce_result ->(value, _ctx) { !!value }
8
8
  default_scalar true
9
9
  end
@@ -334,7 +334,7 @@ module GraphQL
334
334
  __typename
335
335
  }
336
336
  }|
337
- res = execute_query(query_string, context: {middleware_log: log})
337
+ execute_query(query_string, context: {middleware_log: log})
338
338
  assert_equal ["node", "__typename"], log
339
339
  end
340
340
 
@@ -61,8 +61,8 @@ module GraphQL
61
61
 
62
62
  timestamp_type = GraphQL::ScalarType.define do
63
63
  name "Timestamp"
64
- coerce_input ->(value) { Time.at(value.to_i) }
65
- coerce_result ->(value) { value.to_i }
64
+ coerce_input ->(value, _ctx) { Time.at(value.to_i) }
65
+ coerce_result ->(value, _ctx) { value.to_i }
66
66
  end
67
67
 
68
68
  named_entity_interface_type = GraphQL::InterfaceType.define do
@@ -162,7 +162,7 @@ module GraphQL
162
162
  |
163
163
 
164
164
  log = []
165
- res = self.class.lazy_schema.execute(query_str, context: {lazy_instrumentation: log, pushes: []})
165
+ self.class.lazy_schema.execute(query_str, context: {lazy_instrumentation: log, pushes: []})
166
166
  expected_log = [
167
167
  "PUSH",
168
168
  "Query.push: 1",
@@ -105,35 +105,13 @@ module GraphQL
105
105
  GraphQL::TypeKinds::ENUM
106
106
  end
107
107
 
108
- def validate_non_null_input(value_name, warden)
109
- result = GraphQL::Query::InputValidationResult.new
110
- allowed_values = warden.enum_values(self)
111
- matching_value = allowed_values.find { |v| v.name == value_name }
112
-
113
- if matching_value.nil?
114
- result.add_problem("Expected #{GraphQL::Language.serialize(value_name)} to be one of: #{allowed_values.map(&:name).join(', ')}")
108
+ def coerce_result(value, ctx = nil)
109
+ if ctx.nil?
110
+ warn_deprecated_coerce("coerce_isolated_result")
111
+ ctx = GraphQL::Query::NullContext
115
112
  end
116
113
 
117
- result
118
- end
119
-
120
- # Get the underlying value for this enum value
121
- #
122
- # @example get episode value from Enum
123
- # episode = EpisodeEnum.coerce("NEWHOPE")
124
- # episode # => 6
125
- #
126
- # @param value_name [String] the string representation of this enum value
127
- # @return [Object] the underlying value for this enum value
128
- def coerce_non_null_input(value_name)
129
- if @values_by_name.key?(value_name)
130
- @values_by_name.fetch(value_name).value
131
- else
132
- nil
133
- end
134
- end
135
-
136
- def coerce_result(value, warden = nil)
114
+ warden = ctx.warden
137
115
  all_values = warden ? warden.enum_values(self) : @values_by_name.each_value
138
116
  enum_value = all_values.find { |val| val.value == value }
139
117
  if enum_value
@@ -160,5 +138,35 @@ module GraphQL
160
138
 
161
139
  class UnresolvedValueError < GraphQL::Error
162
140
  end
141
+
142
+ private
143
+
144
+ # Get the underlying value for this enum value
145
+ #
146
+ # @example get episode value from Enum
147
+ # episode = EpisodeEnum.coerce("NEWHOPE")
148
+ # episode # => 6
149
+ #
150
+ # @param value_name [String] the string representation of this enum value
151
+ # @return [Object] the underlying value for this enum value
152
+ def coerce_non_null_input(value_name, ctx)
153
+ if @values_by_name.key?(value_name)
154
+ @values_by_name.fetch(value_name).value
155
+ else
156
+ nil
157
+ end
158
+ end
159
+
160
+ def validate_non_null_input(value_name, ctx)
161
+ result = GraphQL::Query::InputValidationResult.new
162
+ allowed_values = ctx.warden.enum_values(self)
163
+ matching_value = allowed_values.find { |v| v.name == value_name }
164
+
165
+ if matching_value.nil?
166
+ result.add_problem("Expected #{GraphQL::Language.serialize(value_name)} to be one of: #{allowed_values.map(&:name).join(', ')}")
167
+ end
168
+
169
+ result
170
+ end
163
171
  end
164
172
  end
@@ -23,8 +23,6 @@ module GraphQL
23
23
  private
24
24
 
25
25
  def resolve_selection(object, current_type, selection, query_ctx, mutation: false )
26
- query = query_ctx.query
27
-
28
26
  selection_result = SelectionResult.new
29
27
 
30
28
  selection.typed_children[current_type].each do |name, subselection|
@@ -143,9 +141,9 @@ module GraphQL
143
141
  else
144
142
  case field_type.kind
145
143
  when GraphQL::TypeKinds::SCALAR
146
- field_type.coerce_result(value)
144
+ field_type.coerce_result(value, field_ctx)
147
145
  when GraphQL::TypeKinds::ENUM
148
- field_type.coerce_result(value, field_ctx.query.warden)
146
+ field_type.coerce_result(value, field_ctx)
149
147
  when GraphQL::TypeKinds::LIST
150
148
  inner_type = field_type.of_type
151
149
  i = 0
@@ -174,7 +172,7 @@ module GraphQL
174
172
  result
175
173
  when GraphQL::TypeKinds::NON_NULL
176
174
  wrapped_type = field_type.of_type
177
- inner_value = resolve_value(
175
+ resolve_value(
178
176
  owner,
179
177
  parent_type,
180
178
  field_defn,
@@ -43,7 +43,7 @@ module GraphQL
43
43
  private
44
44
 
45
45
  def find_superclass_method(value_class)
46
- @storage.each { |lazy_class, lazy_value_method|
46
+ @storage.each_pair { |lazy_class, lazy_value_method|
47
47
  return lazy_value_method if value_class < lazy_class
48
48
  }
49
49
  nil
@@ -54,7 +54,7 @@ module GraphQL
54
54
  extend Forwardable
55
55
  # Technically this should be under the mutex too,
56
56
  # but I know it's only used when the lock is already acquired.
57
- def_delegators :@storage, :each, :size
57
+ def_delegators :@storage, :each_pair, :size
58
58
 
59
59
  def initialize
60
60
  @semaphore = Mutex.new
@@ -3,7 +3,7 @@ GraphQL::FLOAT_TYPE = GraphQL::ScalarType.define do
3
3
  name "Float"
4
4
  description "Represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)."
5
5
 
6
- coerce_input ->(value) { value.is_a?(Numeric) ? value.to_f : nil }
7
- coerce_result ->(value) { value.to_f }
6
+ coerce_input ->(value, _ctx) { value.is_a?(Numeric) ? value.to_f : nil }
7
+ coerce_result ->(value, _ctx) { value.to_f }
8
8
  default_scalar true
9
9
  end
@@ -78,6 +78,11 @@ module GraphQL
78
78
  end
79
79
  end
80
80
 
81
+ # Provides shorthand access to GraphQL's built-in types
82
+ def types
83
+ GraphQL::Define::TypeDefiner.instance
84
+ end
85
+
81
86
  # Get or set the return type for this function class & descendants
82
87
  # @return [GraphQL::BaseType]
83
88
  def type(premade_type = nil, &block)
@@ -3,8 +3,8 @@ GraphQL::ID_TYPE = GraphQL::ScalarType.define do
3
3
  name "ID"
4
4
  description "Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"VXNlci0xMA==\"`) or integer (such as `4`) input value will be accepted as an ID."
5
5
 
6
- coerce_result ->(value) { value.to_s }
7
- coerce_input ->(value) {
6
+ coerce_result ->(value, _ctx) { value.to_s }
7
+ coerce_input ->(value, _ctx) {
8
8
  case value
9
9
  when String, Integer
10
10
  value.to_s
@@ -55,7 +55,51 @@ module GraphQL
55
55
  GraphQL::TypeKinds::INPUT_OBJECT
56
56
  end
57
57
 
58
- def validate_non_null_input(input, warden)
58
+ def coerce_result(value, ctx = nil)
59
+ if ctx.nil?
60
+ warn_deprecated_coerce("coerce_isolated_result")
61
+ ctx = GraphQL::Query::NullContext
62
+ end
63
+
64
+ # Allow the application to provide values as :symbols, and convert them to the strings
65
+ value = value.reduce({}) { |memo, (k, v)| memo[k.to_s] = v; memo }
66
+
67
+ result = {}
68
+
69
+ arguments.each do |input_key, input_field_defn|
70
+ input_value = value[input_key]
71
+ if value.key?(input_key)
72
+ result[input_key] = if input_value.nil?
73
+ nil
74
+ else
75
+ input_field_defn.type.coerce_result(input_value, ctx)
76
+ end
77
+ end
78
+ end
79
+
80
+ result
81
+ end
82
+
83
+ private
84
+
85
+ def coerce_non_null_input(value, ctx)
86
+ input_values = {}
87
+
88
+ arguments.each do |input_key, input_field_defn|
89
+ field_value = value[input_key]
90
+
91
+ if value.key?(input_key)
92
+ input_values[input_key] = input_field_defn.type.coerce_input(field_value, ctx)
93
+ elsif input_field_defn.default_value?
94
+ input_values[input_key] = input_field_defn.default_value
95
+ end
96
+ end
97
+
98
+ GraphQL::Query::Arguments.new(input_values, argument_definitions: arguments)
99
+ end
100
+
101
+ def validate_non_null_input(input, ctx)
102
+ warden = ctx.warden
59
103
  result = GraphQL::Query::InputValidationResult.new
60
104
 
61
105
  if (input.to_h rescue nil).nil?
@@ -78,7 +122,7 @@ module GraphQL
78
122
 
79
123
  # Items in the input that are expected, but have invalid values
80
124
  visible_arguments_map.map do |name, field|
81
- field_result = field.type.validate_input(input[name], warden)
125
+ field_result = field.type.validate_input(input[name], ctx)
82
126
  if !field_result.valid?
83
127
  result.merge_result!(name, field_result)
84
128
  end
@@ -86,39 +130,5 @@ module GraphQL
86
130
 
87
131
  result
88
132
  end
89
-
90
- def coerce_non_null_input(value)
91
- input_values = {}
92
-
93
- arguments.each do |input_key, input_field_defn|
94
- field_value = value[input_key]
95
-
96
- if value.key?(input_key)
97
- coerced_value = input_field_defn.type.coerce_input(field_value)
98
- else
99
- coerced_value = input_field_defn.default_value
100
- end
101
-
102
- if coerced_value || value.key?(input_key)
103
- input_values[input_key] = coerced_value
104
- end
105
- end
106
-
107
- GraphQL::Query::Arguments.new(input_values, argument_definitions: arguments)
108
- end
109
-
110
- def coerce_result(value)
111
- # Allow the application to provide values as :symbols, and convert them to the strings
112
- value = value.reduce({}) { |memo, (k, v)| memo[k.to_s] = v; memo }
113
-
114
- result = {}
115
-
116
- arguments.each do |input_key, input_field_defn|
117
- input_value = value[input_key]
118
- result[input_key] = input_value.nil? ? nil : input_field_defn.type.coerce_result(input_value) if value.key?(input_key)
119
- end
120
-
121
- result
122
- end
123
133
  end
124
134
  end