rails-graphql 1.0.0.beta → 1.0.0.rc2
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.
- checksums.yaml +4 -4
- data/ext/gql_parser.c +1 -16
- data/ext/gql_parser.h +21 -0
- data/ext/shared.c +0 -5
- data/ext/shared.h +6 -6
- data/lib/generators/graphql/channel_generator.rb +27 -0
- data/lib/generators/graphql/controller_generator.rb +9 -4
- data/lib/generators/graphql/install_generator.rb +49 -0
- data/lib/generators/graphql/schema_generator.rb +9 -4
- data/lib/generators/graphql/templates/channel.erb +7 -0
- data/lib/generators/graphql/templates/config.rb +97 -0
- data/lib/generators/graphql/templates/controller.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +5 -3
- data/lib/gql_parser.so +0 -0
- data/lib/rails/graphql/alternative/field_set.rb +12 -0
- data/lib/rails/graphql/alternative/query.rb +13 -8
- data/lib/rails/graphql/alternative/subscription.rb +2 -1
- data/lib/rails/graphql/alternative.rb +4 -0
- data/lib/rails/graphql/argument.rb +5 -3
- data/lib/rails/graphql/callback.rb +10 -8
- data/lib/rails/graphql/collectors/hash_collector.rb +12 -1
- data/lib/rails/graphql/collectors/json_collector.rb +21 -0
- data/lib/rails/graphql/config.rb +86 -59
- data/lib/rails/graphql/directive/include_directive.rb +0 -1
- data/lib/rails/graphql/directive/skip_directive.rb +0 -1
- data/lib/rails/graphql/directive/specified_by_directive.rb +24 -0
- data/lib/rails/graphql/directive.rb +31 -25
- data/lib/rails/graphql/event.rb +7 -6
- data/lib/rails/graphql/field/authorized_field.rb +0 -5
- data/lib/rails/graphql/field/input_field.rb +0 -5
- data/lib/rails/graphql/field/mutation_field.rb +5 -6
- data/lib/rails/graphql/field/output_field.rb +13 -2
- data/lib/rails/graphql/field/proxied_field.rb +6 -6
- data/lib/rails/graphql/field/resolved_field.rb +1 -1
- data/lib/rails/graphql/field/subscription_field.rb +35 -52
- data/lib/rails/graphql/field/typed_field.rb +26 -2
- data/lib/rails/graphql/field.rb +20 -19
- data/lib/rails/graphql/global_id.rb +5 -1
- data/lib/rails/graphql/helpers/inherited_collection/array.rb +1 -0
- data/lib/rails/graphql/helpers/inherited_collection/base.rb +3 -1
- data/lib/rails/graphql/helpers/inherited_collection/hash.rb +2 -1
- data/lib/rails/graphql/helpers/registerable.rb +1 -1
- data/lib/rails/graphql/helpers/with_arguments.rb +3 -2
- data/lib/rails/graphql/helpers/with_assignment.rb +5 -5
- data/lib/rails/graphql/helpers/with_callbacks.rb +3 -3
- data/lib/rails/graphql/helpers/with_description.rb +10 -8
- data/lib/rails/graphql/helpers/with_directives.rb +5 -1
- data/lib/rails/graphql/helpers/with_events.rb +1 -0
- data/lib/rails/graphql/helpers/with_fields.rb +30 -24
- data/lib/rails/graphql/helpers/with_name.rb +3 -2
- data/lib/rails/graphql/helpers/with_schema_fields.rb +75 -51
- data/lib/rails/graphql/introspection.rb +1 -1
- data/lib/rails/graphql/railtie.rb +3 -2
- data/lib/rails/graphql/railties/app/base_channel.rb +10 -0
- data/lib/rails/graphql/railties/app/base_controller.rb +12 -0
- data/lib/rails/graphql/railties/app/views/_cable.js.erb +56 -0
- data/lib/rails/graphql/railties/app/views/_fetch.js.erb +20 -0
- data/lib/rails/graphql/railties/app/views/graphiql.html.erb +101 -0
- data/lib/rails/graphql/railties/base_generator.rb +3 -9
- data/lib/rails/graphql/railties/channel.rb +8 -8
- data/lib/rails/graphql/railties/controller.rb +51 -26
- data/lib/rails/graphql/request/arguments.rb +2 -1
- data/lib/rails/graphql/request/backtrace.rb +31 -10
- data/lib/rails/graphql/request/component/field.rb +15 -8
- data/lib/rails/graphql/request/component/fragment.rb +13 -7
- data/lib/rails/graphql/request/component/operation/subscription.rb +4 -6
- data/lib/rails/graphql/request/component/operation.rb +12 -5
- data/lib/rails/graphql/request/component/spread.rb +13 -4
- data/lib/rails/graphql/request/component/typename.rb +1 -1
- data/lib/rails/graphql/request/component.rb +2 -0
- data/lib/rails/graphql/request/context.rb +1 -1
- data/lib/rails/graphql/request/event.rb +6 -2
- data/lib/rails/graphql/request/helpers/directives.rb +1 -0
- data/lib/rails/graphql/request/helpers/selection_set.rb +10 -4
- data/lib/rails/graphql/request/helpers/value_writers.rb +8 -5
- data/lib/rails/graphql/request/prepared_data.rb +3 -1
- data/lib/rails/graphql/request/steps/organizable.rb +1 -1
- data/lib/rails/graphql/request/steps/preparable.rb +1 -1
- data/lib/rails/graphql/request/steps/resolvable.rb +1 -1
- data/lib/rails/graphql/request/strategy/sequenced_strategy.rb +3 -3
- data/lib/rails/graphql/request/strategy.rb +18 -4
- data/lib/rails/graphql/request/subscription.rb +18 -16
- data/lib/rails/graphql/request.rb +71 -41
- data/lib/rails/graphql/schema.rb +39 -86
- data/lib/rails/graphql/shortcuts.rb +11 -5
- data/lib/rails/graphql/source/active_record/builders.rb +22 -24
- data/lib/rails/graphql/source/active_record_source.rb +96 -34
- data/lib/rails/graphql/source/base.rb +13 -40
- data/lib/rails/graphql/source/builder.rb +14 -22
- data/lib/rails/graphql/source/scoped_arguments.rb +10 -4
- data/lib/rails/graphql/source.rb +31 -38
- data/lib/rails/graphql/subscription/provider/action_cable.rb +10 -9
- data/lib/rails/graphql/subscription/provider/base.rb +6 -5
- data/lib/rails/graphql/subscription/store/base.rb +5 -9
- data/lib/rails/graphql/subscription/store/memory.rb +18 -9
- data/lib/rails/graphql/type/creator.rb +198 -0
- data/lib/rails/graphql/type/enum.rb +17 -9
- data/lib/rails/graphql/type/input.rb +30 -7
- data/lib/rails/graphql/type/interface.rb +15 -4
- data/lib/rails/graphql/type/object/directive_object.rb +6 -5
- data/lib/rails/graphql/type/object/input_value_object.rb +3 -4
- data/lib/rails/graphql/type/object/type_object.rb +40 -13
- data/lib/rails/graphql/type/object.rb +11 -6
- data/lib/rails/graphql/type/scalar/binary_scalar.rb +2 -0
- data/lib/rails/graphql/type/scalar/date_scalar.rb +2 -0
- data/lib/rails/graphql/type/scalar/date_time_scalar.rb +2 -0
- data/lib/rails/graphql/type/scalar/decimal_scalar.rb +2 -0
- data/lib/rails/graphql/type/scalar/json_scalar.rb +3 -1
- data/lib/rails/graphql/type/scalar/time_scalar.rb +3 -1
- data/lib/rails/graphql/type/scalar.rb +2 -2
- data/lib/rails/graphql/type/union.rb +7 -2
- data/lib/rails/graphql/type.rb +10 -2
- data/lib/rails/graphql/type_map.rb +20 -7
- data/lib/rails/graphql/uri.rb +5 -4
- data/lib/rails/graphql/version.rb +6 -2
- data/lib/rails/graphql.rb +11 -8
- data/test/assets/introspection-mem.txt +1 -1
- data/test/assets/introspection.gql +2 -0
- data/test/assets/mem.gql +74 -60
- data/test/assets/mysql.gql +69 -55
- data/test/assets/sqlite.gql +78 -64
- data/test/assets/translate.gql +50 -39
- data/test/config.rb +2 -1
- data/test/graphql/schema_test.rb +2 -31
- data/test/graphql/source_test.rb +1 -11
- data/test/graphql/type/interface_test.rb +8 -5
- data/test/graphql/type/object_test.rb +8 -2
- data/test/graphql/type_map_test.rb +13 -16
- data/test/integration/global_id_test.rb +4 -4
- data/test/integration/memory/star_wars_validation_test.rb +2 -2
- data/test/integration/mysql/star_wars_introspection_test.rb +1 -1
- data/test/integration/resolver_precedence_test.rb +1 -1
- data/test/integration/schemas/memory.rb +3 -4
- data/test/integration/sqlite/star_wars_global_id_test.rb +27 -21
- data/test/integration/sqlite/star_wars_introspection_test.rb +1 -1
- data/test/integration/translate_test.rb +26 -14
- metadata +22 -9
@@ -4,21 +4,28 @@ module Rails
|
|
4
4
|
module GraphQL
|
5
5
|
# = GraphQL Subscription Field
|
6
6
|
#
|
7
|
-
#
|
7
|
+
# This is an extension of a normal output field, which will sign
|
8
|
+
# the request for updates of the field when the scope and arguments
|
9
|
+
# are the same.
|
8
10
|
class Field::SubscriptionField < Field::OutputField
|
9
11
|
redefine_singleton_method(:subscription?) { true }
|
10
12
|
event_types(:subscribed, append: true)
|
11
13
|
|
12
|
-
attr_reader :prepare_context
|
13
|
-
|
14
14
|
module Proxied # :nodoc: all
|
15
15
|
def full_scope
|
16
16
|
field.full_scope + super
|
17
17
|
end
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
# Just add the callbacks setup to the field
|
21
|
+
def self.included(other)
|
22
|
+
other.send(:expose_events!, :subscribed)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Intercept the initializer to maybe set the +scope+
|
26
|
+
def initialize(*args, scope: nil, **xargs, &block)
|
27
|
+
@scope = Array.wrap(scope).freeze unless scope.nil?
|
28
|
+
super(*args, **xargs, &block)
|
22
29
|
end
|
23
30
|
|
24
31
|
# Change the schema type of the field
|
@@ -26,72 +33,63 @@ module Rails
|
|
26
33
|
:subscription
|
27
34
|
end
|
28
35
|
|
29
|
-
# A kind of alias to the subscribe event available
|
30
|
-
def subscribed(*args, **xargs, &block)
|
31
|
-
on(:subscribed, *args, **xargs, &block)
|
32
|
-
self
|
33
|
-
end
|
34
|
-
|
35
36
|
# Set the parts of the scope of the subscription
|
36
37
|
def scope(*parts)
|
37
38
|
(defined?(@scope) ? (@scope += parts) : (@scope = parts)).freeze
|
39
|
+
self
|
38
40
|
end
|
39
41
|
|
40
42
|
# Get the full scope of the field
|
41
43
|
def full_scope
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
# Checks if the scope is correctly defined
|
46
|
-
def validate!(*)
|
47
|
-
super if defined? super
|
48
|
-
return unless defined?(@scope)
|
49
|
-
|
50
|
-
invalid = @scope.reject { |item| item.is_a?(Symbol) || item.is_a?(Proc) }
|
51
|
-
raise ArgumentError, (+<<~MSG).squish if invalid.any?
|
52
|
-
The "#{type_klass.gql_name}" has invalid values set for its scope: #{invalid.inspect}.
|
53
|
-
MSG
|
44
|
+
defined?(@scope) ? @scope : EMPTY_ARRAY
|
54
45
|
end
|
55
46
|
|
56
47
|
# A shortcut for trigger when everything is related to the provided object
|
57
|
-
|
58
|
-
# TODO: Add support for +data_for+. The only problem right now is that
|
59
|
-
# providers run asynchronously, so passing data is a bit more complicated
|
60
|
-
# and maybe dangerous (size speaking)
|
61
|
-
def trigger_for(object, **xargs)
|
62
|
-
match_valid_object!(object)
|
48
|
+
def trigger_for(object, and_prepare: true, **xargs)
|
63
49
|
xargs[:args] ||= extract_args_from(object)
|
50
|
+
|
51
|
+
if and_prepare
|
52
|
+
xargs[:data_for] ||= {}
|
53
|
+
xargs[:data_for][+"subscription.#{gql_name}"] = object
|
54
|
+
end
|
55
|
+
|
64
56
|
trigger(**xargs)
|
65
57
|
end
|
66
58
|
|
67
59
|
# A shortcut for unsubscribe when everything is related to the provided
|
68
60
|
# object
|
69
|
-
# TODO: Maybe add support for object as an array of things
|
70
61
|
def unsubscribe_from(object, **xargs)
|
71
|
-
match_valid_object!(object)
|
72
62
|
xargs[:args] ||= extract_args_from(object)
|
73
63
|
unsubscribe(**xargs)
|
74
64
|
end
|
75
65
|
|
76
66
|
# Trigger an update to the subscription
|
77
|
-
def trigger(
|
67
|
+
def trigger(**xargs)
|
78
68
|
provider = owner.subscription_provider
|
79
|
-
provider.search_and_update(field: self,
|
69
|
+
provider.search_and_update(field: self, **xargs)
|
80
70
|
end
|
81
71
|
|
82
72
|
# Force matching subscriptions to be removed
|
83
|
-
def unsubscribe(
|
73
|
+
def unsubscribe(**xargs)
|
84
74
|
provider = owner.subscription_provider
|
85
|
-
provider.search_and_remove(field: self,
|
75
|
+
provider.search_and_remove(field: self, **xargs)
|
86
76
|
end
|
87
77
|
|
88
78
|
protected
|
89
79
|
|
90
80
|
# Match any argument with properties from the given +object+ so it
|
91
81
|
# produces all the possibilities of an update
|
92
|
-
def extract_args_from(object)
|
82
|
+
def extract_args_from(object, iterate = true)
|
93
83
|
return unless arguments?
|
94
84
|
|
85
|
+
# If can iterate and the provided object is an enumerable, then
|
86
|
+
# call itself with each item
|
87
|
+
if iterate && object.is_a?(Enumerable)
|
88
|
+
return object.each_with_object([]) do |item, result|
|
89
|
+
result.concat(extract_args_from(item, false))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
95
93
|
# Prepare all the possibilities
|
96
94
|
keys = []
|
97
95
|
hash_like = object.respond_to?(:[])
|
@@ -116,21 +114,6 @@ module Rails
|
|
116
114
|
end
|
117
115
|
end
|
118
116
|
|
119
|
-
# Check if the provided +object+ is a match for the type that this field
|
120
|
-
# is associated with
|
121
|
-
def match_valid_object!(object)
|
122
|
-
raise ::ArgumentError, (+<<~MSG).squish unless type_klass&.object?
|
123
|
-
Cannot trigger with an object when the field is not associated to
|
124
|
-
an object-like result.
|
125
|
-
MSG
|
126
|
-
|
127
|
-
assignable = !object.is_a?(Module) && type_klass.valid_member?(object)
|
128
|
-
raise ::ArgumentError, (+<<~MSG).squish unless assignable
|
129
|
-
The provided object "#{object.inspect}" is not a valid member of
|
130
|
-
#{type_klass.inspect} for the :#{name} field.
|
131
|
-
MSG
|
132
|
-
end
|
133
|
-
|
134
117
|
def proxied
|
135
118
|
super if defined? super
|
136
119
|
extend Field::SubscriptionField::Proxied
|
@@ -13,7 +13,8 @@ module Rails
|
|
13
13
|
|
14
14
|
delegate :input_type?, :output_type?, :leaf_type?, :kind, to: :type_klass
|
15
15
|
|
16
|
-
def initialize(name, type, *args, **xargs, &block)
|
16
|
+
def initialize(name, type = nil, *args, **xargs, &block)
|
17
|
+
type = (name == :id ? :id : :string) if type.nil?
|
17
18
|
assign_type(type)
|
18
19
|
super(name, *args, **xargs, &block)
|
19
20
|
end
|
@@ -26,7 +27,7 @@ module Rails
|
|
26
27
|
|
27
28
|
# Check if types are compatible
|
28
29
|
def =~(other)
|
29
|
-
other.is_a?(Field::TypedField) && other.type_klass =~ type_klass
|
30
|
+
super && other.is_a?(Field::TypedField) && other.type_klass =~ type_klass
|
30
31
|
end
|
31
32
|
|
32
33
|
# Sometimes the owner does not designate this, but it is safe to assume it
|
@@ -49,6 +50,8 @@ module Rails
|
|
49
50
|
)
|
50
51
|
end
|
51
52
|
|
53
|
+
alias type_class type_klass
|
54
|
+
|
52
55
|
# Add the listeners from the associated type
|
53
56
|
def all_listeners
|
54
57
|
inherited = super
|
@@ -74,6 +77,27 @@ module Rails
|
|
74
77
|
super || type_klass.events?
|
75
78
|
end
|
76
79
|
|
80
|
+
# Transforms the given value to its representation in a JSON string
|
81
|
+
def to_json(value)
|
82
|
+
return 'null' if value.nil?
|
83
|
+
return type_klass.to_json(value) unless array?
|
84
|
+
value.map { |part| type_klass.to_json(part) }
|
85
|
+
end
|
86
|
+
|
87
|
+
# Turn the given value into a JSON string representation
|
88
|
+
def as_json(value)
|
89
|
+
return if value.nil?
|
90
|
+
return type_klass.as_json(value) unless array?
|
91
|
+
value.map { |part| type_klass.as_json(part) }
|
92
|
+
end
|
93
|
+
|
94
|
+
# Turn a user input of this given type into an ruby object
|
95
|
+
def deserialize(value)
|
96
|
+
return if value.nil?
|
97
|
+
return type_klass.deserialize(value) unless array?
|
98
|
+
value.map { |val| type_klass.deserialize(val) unless val.nil? }
|
99
|
+
end
|
100
|
+
|
77
101
|
# Checks if the type of the field is valid
|
78
102
|
def validate!(*)
|
79
103
|
super if defined? super
|
data/lib/rails/graphql/field.rb
CHANGED
@@ -22,7 +22,7 @@ module Rails
|
|
22
22
|
# (defaults to false).
|
23
23
|
# * <tt>:enabled</tt> - Mark the field as enabled
|
24
24
|
# (defaults to true).
|
25
|
-
# * <tt>:disabled</tt> - Works as the
|
25
|
+
# * <tt>:disabled</tt> - Works as the opposite of the enabled option
|
26
26
|
# (defaults to false).
|
27
27
|
# * <tt>:directives</tt> - The list of directives associated with the value
|
28
28
|
# (defaults to nil).
|
@@ -117,7 +117,7 @@ module Rails
|
|
117
117
|
@array = full ? true : xargs.fetch(:array, false)
|
118
118
|
@nullable = full ? false : xargs.fetch(:nullable, true)
|
119
119
|
|
120
|
-
self.description = xargs[:desc]
|
120
|
+
self.description = xargs[:desc] || xargs[:description]
|
121
121
|
@enabled = xargs.fetch(:enabled, !xargs.fetch(:disabled, false))
|
122
122
|
|
123
123
|
configure(&block) if block.present?
|
@@ -137,12 +137,14 @@ module Rails
|
|
137
137
|
enable! if xargs.fetch(:enabled, false)
|
138
138
|
|
139
139
|
self.description = xargs[:desc] if xargs.key?(:desc)
|
140
|
+
self.description = xargs[:description] if xargs.key?(:description)
|
140
141
|
configure(&block) if block.present?
|
141
142
|
end
|
142
143
|
|
143
144
|
# Allow extra configurations to be performed using a block
|
144
145
|
def configure(&block)
|
145
146
|
Field::ScopedConfig.new(self, block.binding.receiver).instance_exec(&block)
|
147
|
+
self
|
146
148
|
end
|
147
149
|
|
148
150
|
# Return the owner as the single item of the list
|
@@ -181,17 +183,22 @@ module Rails
|
|
181
183
|
@nullable = false
|
182
184
|
end
|
183
185
|
|
184
|
-
# Checks if the
|
186
|
+
# Checks if the field can be null
|
185
187
|
def null?
|
186
188
|
!!@null
|
187
189
|
end
|
188
190
|
|
189
|
-
# Checks if the
|
191
|
+
# Checks if the field cannot br null
|
192
|
+
def required?
|
193
|
+
!null?
|
194
|
+
end
|
195
|
+
|
196
|
+
# Checks if the field can be an array
|
190
197
|
def array?
|
191
198
|
!!@array
|
192
199
|
end
|
193
200
|
|
194
|
-
# Checks if the
|
201
|
+
# Checks if the field can have null elements in the array
|
195
202
|
def nullable?
|
196
203
|
!!@nullable
|
197
204
|
end
|
@@ -227,24 +234,18 @@ module Rails
|
|
227
234
|
end
|
228
235
|
|
229
236
|
# Transforms the given value to its representation in a JSON string
|
230
|
-
def to_json(
|
231
|
-
|
232
|
-
return type_klass.to_json(value) unless array?
|
233
|
-
value.map { |part| type_klass.to_json(part) }
|
237
|
+
def to_json(*)
|
238
|
+
raise NotImplementedError, +"#{self.class.name} does not implement to_json"
|
234
239
|
end
|
235
240
|
|
236
241
|
# Turn the given value into a JSON string representation
|
237
|
-
def as_json(
|
238
|
-
|
239
|
-
return type_klass.as_json(value) unless array?
|
240
|
-
value.map { |part| type_klass.as_json(part) }
|
242
|
+
def as_json(*)
|
243
|
+
raise NotImplementedError, +"#{self.class.name} does not implement as_json"
|
241
244
|
end
|
242
245
|
|
243
246
|
# Turn a user input of this given type into an ruby object
|
244
|
-
def deserialize(
|
245
|
-
|
246
|
-
return type_klass.deserialize(value) unless array?
|
247
|
-
value.map { |val| type_klass.deserialize(val) unless val.nil? }
|
247
|
+
def deserialize(*)
|
248
|
+
raise NotImplementedError, +"#{self.class.name} does not implement deserialize"
|
248
249
|
end
|
249
250
|
|
250
251
|
# Check if the given value is valid using +valid_input?+ or
|
@@ -282,8 +283,8 @@ module Rails
|
|
282
283
|
|
283
284
|
def inspect
|
284
285
|
(+<<~INFO).squish << '>'
|
285
|
-
|
286
|
-
#{inspect_owner}
|
286
|
+
#<GraphQL::#{self.class.name.split('::').last}
|
287
|
+
#{inspect_owner&.split(+'GraphQL::')&.last&.sub(+'::NestedTypes', '')}
|
287
288
|
#{inspect_source}
|
288
289
|
#{inspect_enabled}
|
289
290
|
#{gql_name}#{inspect_arguments}#{inspect_type}
|
@@ -72,7 +72,11 @@ module Rails
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def base_class
|
75
|
-
|
75
|
+
if %w[Schema Directive Type].include?(class_name)
|
76
|
+
GraphQL.const_get(class_name, false)
|
77
|
+
else
|
78
|
+
GraphQL.type_map.fetch(class_name, namespace: namespace)
|
79
|
+
end
|
76
80
|
end
|
77
81
|
|
78
82
|
def ==(other)
|
@@ -4,6 +4,7 @@ module Rails
|
|
4
4
|
# A inherited collection of arrays that can be unique when it is a set
|
5
5
|
class InheritedCollection::Array < InheritedCollection::Base
|
6
6
|
alias size count
|
7
|
+
alias to_ary eager
|
7
8
|
|
8
9
|
# Provide similar functionality of any? but returns the object instead
|
9
10
|
def find(value = nil, &block)
|
@@ -7,10 +7,12 @@ module Rails
|
|
7
7
|
class InheritedCollection::Base
|
8
8
|
include Enumerable
|
9
9
|
|
10
|
+
delegate :eager, to: :each
|
11
|
+
|
10
12
|
# Just a little helper to initialize the iterator form a given +source+
|
11
13
|
def self.handle(source, ivar, type)
|
12
14
|
klass = (type == :array || type == :set) ? :Array : :Hash
|
13
|
-
InheritedCollection.const_get(klass).new(source, ivar, type)
|
15
|
+
InheritedCollection.const_get(klass, false).new(source, ivar, type)
|
14
16
|
end
|
15
17
|
|
16
18
|
def initialize(source, ivar, type)
|
@@ -5,6 +5,7 @@ module Rails
|
|
5
5
|
# or sets
|
6
6
|
class InheritedCollection::Hash < InheritedCollection::Base
|
7
7
|
delegate :transform_values, :transform_keys, to: :to_hash
|
8
|
+
delegate :filter_map, :map, to: :eager
|
8
9
|
|
9
10
|
# Simply go over each definition and check for the given key
|
10
11
|
def key?(value)
|
@@ -44,7 +45,7 @@ module Rails
|
|
44
45
|
keys.lazy.map(&method(:[]))
|
45
46
|
end
|
46
47
|
|
47
|
-
# Basically
|
48
|
+
# Basically returns the plain result value
|
48
49
|
def to_hash
|
49
50
|
each.to_h
|
50
51
|
end
|
@@ -25,7 +25,7 @@ module Rails
|
|
25
25
|
GraphQL.type_map.postpone_registration(subclass)
|
26
26
|
end
|
27
27
|
|
28
|
-
# Check if the class is already registered in the
|
28
|
+
# Check if the class is already registered in the type map
|
29
29
|
def registered?
|
30
30
|
GraphQL.type_map.object_exist?(self, exclusive: true)
|
31
31
|
end
|
@@ -59,14 +59,15 @@ module Rails
|
|
59
59
|
end
|
60
60
|
|
61
61
|
# See {Argument}[rdoc-ref:Rails::GraphQL::Argument] class.
|
62
|
-
def argument(name,
|
63
|
-
object = GraphQL::Argument.new(name,
|
62
|
+
def argument(name, type = nil, **xargs)
|
63
|
+
object = GraphQL::Argument.new(name, type, **xargs, owner: self)
|
64
64
|
|
65
65
|
raise DuplicatedError, (+<<~MSG).squish if has_argument?(object.name)
|
66
66
|
The #{name.inspect} argument is already defined and can't be redefined.
|
67
67
|
MSG
|
68
68
|
|
69
69
|
arguments[object.name] = object
|
70
|
+
self
|
70
71
|
rescue DefinitionError => e
|
71
72
|
raise e.class, +"#{e.message}\n Defined at: #{caller(2)[0]}"
|
72
73
|
end
|
@@ -61,12 +61,12 @@ module Rails
|
|
61
61
|
return if abstract?
|
62
62
|
return super unless assigned?
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
super.tap do
|
65
|
+
break unless (klass = safe_assigned_class)
|
66
|
+
break if GraphQL.type_map.exist?(klass, namespaces: namespaces)
|
67
67
|
|
68
|
-
|
69
|
-
|
68
|
+
GraphQL.type_map.register_alias(klass, gql_name, namespaces: namespaces)
|
69
|
+
end
|
70
70
|
end
|
71
71
|
|
72
72
|
protected
|
@@ -5,11 +5,11 @@ module Rails
|
|
5
5
|
module Helpers
|
6
6
|
# Callbacks is an extension of the events which works with the
|
7
7
|
# {Callback}[rdoc-ref:Rails::GraphQL::Callback] class, then having extra
|
8
|
-
# powers when actually executing the event against
|
9
|
-
#
|
8
|
+
# powers when actually executing the event against Procs or owner-based
|
9
|
+
# methods, when provided a symbol
|
10
10
|
module WithCallbacks
|
11
11
|
DEFAULT_EVENT_TYPES = %i[query mutation subscription request attach
|
12
|
-
authorize organized prepared finalize].freeze
|
12
|
+
authorize organized prepared finalize prepare subscribed].freeze
|
13
13
|
|
14
14
|
def self.extended(other)
|
15
15
|
other.extend(WithCallbacks::Setup)
|
@@ -12,17 +12,19 @@ module Rails
|
|
12
12
|
|
13
13
|
# Define and format description
|
14
14
|
def description=(value)
|
15
|
-
|
15
|
+
if !value.nil?
|
16
|
+
@description = value.to_s.presence&.strip_heredoc&.chomp
|
17
|
+
elsif defined?(@description)
|
18
|
+
@description = nil
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
|
-
# Return
|
22
|
+
# Return a description, by defined value or I18n
|
19
23
|
def description(namespace = nil, kind = nil)
|
20
24
|
return @description if description?
|
21
25
|
return unless GraphQL.config.enable_i18n_descriptions
|
22
26
|
|
23
|
-
|
24
|
-
return if defined?(@description)
|
25
|
-
@description = i18n_description(namespace, kind)
|
27
|
+
i18n_description(namespace, kind)
|
26
28
|
end
|
27
29
|
|
28
30
|
# Checks if a description was provided
|
@@ -34,7 +36,8 @@ module Rails
|
|
34
36
|
|
35
37
|
# Return a description from I18n
|
36
38
|
def i18n_description(namespace = nil, kind = nil)
|
37
|
-
return if (parent = try(:owner)).try(:spec_object?)
|
39
|
+
return if (parent = try(:owner)).try(:spec_object?) &&
|
40
|
+
parent.kind != :schema
|
38
41
|
|
39
42
|
values = {
|
40
43
|
kind: kind || try(:kind),
|
@@ -49,8 +52,7 @@ module Rails
|
|
49
52
|
next if key.include?('..')
|
50
53
|
|
51
54
|
result = catch(:exception) { ::I18n.translate(key, throw: true) }
|
52
|
-
return result
|
53
|
-
result.is_a?(I18n::MissingTranslation)
|
55
|
+
return result if result.is_a?(String)
|
54
56
|
end
|
55
57
|
end
|
56
58
|
|
@@ -59,12 +59,14 @@ module Rails
|
|
59
59
|
list << item_or_symbol
|
60
60
|
end
|
61
61
|
|
62
|
-
directives
|
62
|
+
directives.merge(GraphQL.directives_to_set(list, all_directives, source: self))
|
63
|
+
self
|
63
64
|
rescue DefinitionError => e
|
64
65
|
raise e.class, +"#{e.message}\n Defined at: #{caller(2)[0]}"
|
65
66
|
end
|
66
67
|
|
67
68
|
# Check whether a given directive is being used
|
69
|
+
# TODO: This does not work with the instance
|
68
70
|
def using?(item)
|
69
71
|
directive = (item.is_a?(Symbol) || item.is_a?(String)) ? fetch!(item) : item
|
70
72
|
raise ArgumentError, (+<<~MSG).squish unless directive < GraphQL::Directive
|
@@ -76,6 +78,8 @@ module Rails
|
|
76
78
|
|
77
79
|
alias has_directive? using?
|
78
80
|
|
81
|
+
# TODO: Maybe implement a method to fetch a specific directive
|
82
|
+
|
79
83
|
# Override the +all_listeners+ method since callbacks can eventually be
|
80
84
|
# attached to objects that have directives, which then they need to
|
81
85
|
# be combined
|
@@ -19,7 +19,7 @@ module Rails
|
|
19
19
|
fields.each_value(&subclass.method(:proxy_field))
|
20
20
|
end
|
21
21
|
|
22
|
-
# Return the list of
|
22
|
+
# Return the list of fields, only initialize when explicitly told
|
23
23
|
def fields(initialize = nil)
|
24
24
|
return @fields if defined?(@fields)
|
25
25
|
return unless initialize
|
@@ -51,7 +51,7 @@ module Rails
|
|
51
51
|
def field(name, *args, **xargs, &block)
|
52
52
|
object = field_type.new(name, *args, **xargs, owner: self, &block)
|
53
53
|
|
54
|
-
raise DuplicatedError, (+<<~MSG).squish if
|
54
|
+
raise DuplicatedError, (+<<~MSG).squish if has_field?(object.name)
|
55
55
|
The #{name.inspect} field is already defined and can't be redefined.
|
56
56
|
MSG
|
57
57
|
|
@@ -63,13 +63,14 @@ module Rails
|
|
63
63
|
# Add a new field to the list but use a proxy instead of a hard copy of
|
64
64
|
# a given +field+
|
65
65
|
def proxy_field(field, *args, **xargs, &block)
|
66
|
+
field = field.field if field.is_a?(Module) && field <= Alternative::Query
|
66
67
|
raise ArgumentError, (+<<~MSG).squish unless field.is_a?(field_type)
|
67
68
|
The #{field.class.name} is not a valid field.
|
68
69
|
MSG
|
69
70
|
|
70
71
|
xargs[:owner] = self
|
71
72
|
object = field.to_proxy(*args, **xargs, &block)
|
72
|
-
raise DuplicatedError, (+<<~MSG).squish if
|
73
|
+
raise DuplicatedError, (+<<~MSG).squish if has_field?(object.name)
|
73
74
|
The #{field.name.inspect} field is already defined and can't be replaced.
|
74
75
|
MSG
|
75
76
|
|
@@ -99,8 +100,8 @@ module Rails
|
|
99
100
|
list.flatten.map { |item| self[item]&.enable! }
|
100
101
|
end
|
101
102
|
|
102
|
-
# Check
|
103
|
-
def
|
103
|
+
# Check whether a given field +object+ is defined in the list of fields
|
104
|
+
def has_field?(object)
|
104
105
|
return false unless fields?
|
105
106
|
object = object.name if object.is_a?(GraphQL::Field)
|
106
107
|
fields.key?(object.is_a?(String) ? object.underscore.to_sym : object)
|
@@ -122,7 +123,7 @@ module Rails
|
|
122
123
|
MSG
|
123
124
|
end
|
124
125
|
|
125
|
-
# Get the list of GraphQL names of all the fields
|
126
|
+
# Get the list of GraphQL names of all the fields defined
|
126
127
|
def field_names(enabled_only = true)
|
127
128
|
(enabled_only ? enabled_fields : lazy_each_field)&.map(&:gql_name)&.eager
|
128
129
|
end
|
@@ -133,32 +134,35 @@ module Rails
|
|
133
134
|
end
|
134
135
|
|
135
136
|
# Import one or more field into the current list of fields
|
136
|
-
def import(
|
137
|
-
|
137
|
+
def import(source)
|
138
|
+
# Import an alternative declaration of a field
|
139
|
+
if source.is_a?(Module) && source <= Alternative::Query
|
140
|
+
return proxy_field(type, source.field)
|
141
|
+
end
|
138
142
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
+
case source
|
144
|
+
when Array
|
145
|
+
# Import a list of fields
|
146
|
+
source.each { |field| proxy_field(type, field) }
|
147
|
+
when Hash, Concurrent::Map
|
148
|
+
# Import a keyed list of fields
|
149
|
+
source.each_value { |field| proxy_field(type, field) }
|
150
|
+
when Helpers::WithFields
|
143
151
|
# Import a set of fields
|
144
|
-
|
152
|
+
source.fields.each_value { |field| proxy_field(type, field) }
|
145
153
|
else
|
146
154
|
return if GraphQL.config.silence_import_warnings
|
147
|
-
GraphQL.logger.warn(+"Unable to import #{
|
155
|
+
GraphQL.logger.warn(+"Unable to import #{source.inspect} into #{self.name}.")
|
148
156
|
end
|
149
157
|
end
|
150
158
|
|
151
159
|
# Import a module containing several classes to be imported
|
152
|
-
def import_all(mod, recursive: false,
|
160
|
+
def import_all(mod, recursive: false, **xargs)
|
153
161
|
mod.constants.each do |const_name|
|
154
|
-
object = mod.const_get(const_name)
|
155
|
-
|
156
|
-
if object.is_a?(Class)
|
157
|
-
|
158
|
-
elsif object.is_a?(Module) && recursive
|
159
|
-
# TODO: Maybe add deepness into the recursive value
|
160
|
-
import_all(object, recursive: recursive, ignore_abstract: ignore_abstract)
|
161
|
-
end
|
162
|
+
object = mod.const_get(const_name, false)
|
163
|
+
|
164
|
+
import(object, **xargs) if object.is_a?(Class)
|
165
|
+
import_all(object, recursive: recursive, **xargs) if recursive && object.is_a?(Module)
|
162
166
|
end
|
163
167
|
end
|
164
168
|
|
@@ -179,11 +183,13 @@ module Rails
|
|
179
183
|
protected
|
180
184
|
|
181
185
|
# A little helper to define arguments using the :arguments key
|
182
|
-
def
|
186
|
+
def argument(*args, **xargs, &block)
|
183
187
|
xargs[:owner] = self
|
184
188
|
GraphQL::Argument.new(*args, **xargs, &block)
|
185
189
|
end
|
186
190
|
|
191
|
+
alias arg argument
|
192
|
+
|
187
193
|
private
|
188
194
|
|
189
195
|
def lazy_each_field
|
@@ -7,7 +7,7 @@ module Rails
|
|
7
7
|
module Helpers
|
8
8
|
# Helper module responsible for name stuff
|
9
9
|
module WithName
|
10
|
-
NAME_EXP = /GraphQL::(?:Type::\w+::|Directive::)?([:\w]
|
10
|
+
NAME_EXP = /GraphQL::(?:Type::\w+::|Directive::)?([:\w]+)\z/.freeze
|
11
11
|
|
12
12
|
# Here we define a couple of attributes used by registration
|
13
13
|
def self.extended(other)
|
@@ -20,7 +20,8 @@ module Rails
|
|
20
20
|
# Return the name of the object as a GraphQL name
|
21
21
|
def gql_name
|
22
22
|
@gql_name ||= begin
|
23
|
-
name.match(NAME_EXP).try(:[], 1)
|
23
|
+
result = name.match(NAME_EXP).try(:[], 1)
|
24
|
+
result.tr(':', '').chomp(base_type.name.demodulize) unless result.nil?
|
24
25
|
end unless anonymous?
|
25
26
|
end
|
26
27
|
|