rails-graphql 1.0.2 → 1.0.5
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/lib/gql_parser.so +0 -0
- data/lib/rails/graphql/config.rb +2 -0
- data/lib/rails/graphql/field/output_field.rb +4 -0
- data/lib/rails/graphql/helpers/attribute_delegator.rb +8 -1
- data/lib/rails/graphql/helpers/with_arguments.rb +5 -0
- data/lib/rails/graphql/railtie.rb +3 -7
- data/lib/rails/graphql/railties/log_subscriber.rb +2 -1
- data/lib/rails/graphql/request/backtrace.rb +4 -1
- data/lib/rails/graphql/request/component/field.rb +1 -1
- data/lib/rails/graphql/request/steps/organizable.rb +2 -2
- data/lib/rails/graphql/source/base.rb +30 -2
- data/lib/rails/graphql/uri.rb +2 -0
- data/lib/rails/graphql/version.rb +1 -1
- data/lib/rails/graphql.rb +1 -0
- data/test/assets/sqlite.gql +4 -0
- data/test/config.rb +1 -0
- data/test/graphql/source_test.rb +10 -0
- data/test/integration/alternative_test.rb +1 -1
- data/test/integration/memory/star_wars_query_test.rb +14 -0
- data/test/integration/memory/star_wars_validation_test.rb +14 -1
- data/test/integration/schemas/mysql.rb +1 -1
- data/test/integration/schemas/sqlite.rb +9 -2
- data/test/integration/sqlite/star_wars_query_test.rb +7 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e7e0b35058deec4afd328520ed24fcd24fe4b0f8765b064b0ff0005398e9e7a
|
4
|
+
data.tar.gz: 0ef41b6819bbbe8057fa203ff6f008812e385030d3c171b401ac051a5890d756
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14d030f7f42f0096d30d0fe9eab85baf3b52526ad5432620a16fa2288e6cfc5e0c123b8f433c78d1155a1dc0869ce5c7567bcdd3b6ff6eef5eca3de1d13ab399
|
7
|
+
data.tar.gz: 933ce0bcb53a39d436a1ff60056882d187bdcf4ec6a76b883f91724b550cdb81164a16e2bc91642db8e2093a76f3c20138ea8fa2ae92772e626352d3807f1adb
|
data/lib/gql_parser.so
CHANGED
Binary file
|
data/lib/rails/graphql/config.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module Rails
|
4
4
|
module GraphQL
|
5
|
+
AR710 = (ActiveRecord.gem_version >= Gem::Version.new('7.1.0'))
|
6
|
+
|
5
7
|
configure do |config|
|
6
8
|
# This helps to keep track of when things were cached and registered. Cached
|
7
9
|
# objects with mismatching versions need to be upgraded or simply reloaded.
|
@@ -5,13 +5,20 @@ module Rails
|
|
5
5
|
module Helpers
|
6
6
|
# This is an extra magic on top of the delegator class from the standard
|
7
7
|
# lib that allows fetching a specific property of the delegated object
|
8
|
-
class AttributeDelegator <
|
8
|
+
class AttributeDelegator < ::BasicObject
|
9
|
+
undef_method :==
|
10
|
+
undef_method :equal?
|
11
|
+
|
9
12
|
def initialize(obj = nil, attribute = nil, cache: true, &block)
|
10
13
|
@delegate_sd_attr = attribute
|
11
14
|
@delegate_sd_obj = block.presence || obj
|
12
15
|
@delegate_cache = cache
|
13
16
|
end
|
14
17
|
|
18
|
+
def raise(*args)
|
19
|
+
::Object.send(:raise, *args)
|
20
|
+
end
|
21
|
+
|
15
22
|
private
|
16
23
|
|
17
24
|
def respond_to_missing?(method_name, include_private = false)
|
@@ -100,6 +100,11 @@ module Rails
|
|
100
100
|
defined?(@arguments) && @arguments.key?(name)
|
101
101
|
end
|
102
102
|
|
103
|
+
# Check if any argument has been defined at all
|
104
|
+
def has_arguments?
|
105
|
+
defined?(@arguments) && !@arguments.empty?
|
106
|
+
end
|
107
|
+
|
103
108
|
# Validate all the arguments to make sure the definition is valid
|
104
109
|
def validate!(*)
|
105
110
|
super if defined? super
|
@@ -29,13 +29,9 @@ module Rails
|
|
29
29
|
# Ensure a valid logger
|
30
30
|
initializer 'graphql.logger' do |app|
|
31
31
|
ActiveSupport.on_load(:graphql) do
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if logger.respond_to?(:tagged)
|
36
|
-
config.logger = logger
|
37
|
-
else
|
38
|
-
config.logger = ActiveSupport::TaggedLogging.new(logger)
|
32
|
+
config.logger ||= begin
|
33
|
+
logger = ::Rails.logger
|
34
|
+
logger.respond_to?(:tagged) ? logger : ActiveSupport::TaggedLogging.new(logger)
|
39
35
|
end
|
40
36
|
end
|
41
37
|
end
|
@@ -98,7 +98,8 @@ module Rails
|
|
98
98
|
parts = [' GraphQL', suffix.presence, event.payload[:name]]
|
99
99
|
parts << "(#{duration}ms)" unless duration.zero?
|
100
100
|
|
101
|
-
|
101
|
+
style = AR710 ? { bold: true } : true
|
102
|
+
color(parts.compact.join(' '), MAGENTA, style)
|
102
103
|
end
|
103
104
|
|
104
105
|
def debug_variables(vars)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_support/parameter_filter'
|
4
|
+
|
3
5
|
module Rails
|
4
6
|
module GraphQL
|
5
7
|
class Request
|
@@ -130,7 +132,8 @@ module Rails
|
|
130
132
|
return '{}' if value.blank?
|
131
133
|
|
132
134
|
request.cache(:backtrace_arguments_filter) do
|
133
|
-
|
135
|
+
filters = GraphQL.config.filter_parameters || EMPTY_ARRAY
|
136
|
+
ActiveSupport::ParameterFilter.new(filters)
|
134
137
|
end.filter(value)
|
135
138
|
end
|
136
139
|
|
@@ -16,7 +16,7 @@ module Rails
|
|
16
16
|
delegate :decorate, to: :type_klass
|
17
17
|
delegate :operation, :variables, :request, to: :parent
|
18
18
|
delegate :method_name, :resolver, :performer, :type_klass, :leaf_type?,
|
19
|
-
:dynamic_resolver?, :mutation?, to: :field
|
19
|
+
:dynamic_resolver?, :has_arguments?, :mutation?, to: :field
|
20
20
|
|
21
21
|
attr_reader :name, :alias_name, :parent, :field, :arguments, :current_object
|
22
22
|
|
@@ -118,9 +118,9 @@ module Rails
|
|
118
118
|
# Helper parser for arguments that also collect necessary variables
|
119
119
|
# Default values forces this method to run even without nodes
|
120
120
|
def parse_arguments(nodes)
|
121
|
-
return @arguments = EMPTY_HASH if nodes.blank?
|
121
|
+
return @arguments = EMPTY_HASH if nodes.blank? && !self.has_arguments?
|
122
122
|
|
123
|
-
args = nodes
|
123
|
+
args = nodes&.each_with_object({}) do |(name, value, var_name), hash|
|
124
124
|
hash[name.to_s] = var_name.nil? ? value : var_name
|
125
125
|
end
|
126
126
|
|
@@ -41,7 +41,9 @@ module Rails
|
|
41
41
|
# to the +::GraphQL+ namespace with the addition of any namespace of
|
42
42
|
# the current class
|
43
43
|
def object
|
44
|
-
@object ||= create_type(superclass: object_class, gql_name: object_name)
|
44
|
+
@object ||= create_type(superclass: object_class, gql_name: object_name).tap do |t|
|
45
|
+
t.include(const_get(:ObjectMethods)) if const_defined?(:ObjectMethods, false)
|
46
|
+
end
|
45
47
|
end
|
46
48
|
|
47
49
|
# Return the GraphQL input type associated with the source. It will
|
@@ -49,7 +51,9 @@ module Rails
|
|
49
51
|
# to the +::GraphQL+ namespace with the addition of any namespace of
|
50
52
|
# the current class
|
51
53
|
def input
|
52
|
-
@input ||= create_type(superclass: input_class, gql_name: input_name)
|
54
|
+
@input ||= create_type(superclass: input_class, gql_name: input_name).tap do |t|
|
55
|
+
t.include(const_get(:InputMethods)) if const_defined?(:InputMethods, false)
|
56
|
+
end
|
53
57
|
end
|
54
58
|
|
55
59
|
protected
|
@@ -77,6 +81,30 @@ module Rails
|
|
77
81
|
GraphQL::Type.create!(self, name, superclass, **xargs, &block)
|
78
82
|
end
|
79
83
|
|
84
|
+
# Allow setting methods on the source object via a proper module
|
85
|
+
def object_methods(&block)
|
86
|
+
type_extend_with_module(:object, &block)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Allow setting methods on the source input via a proper module
|
90
|
+
def input_methods(&block)
|
91
|
+
type_extend_with_module(:input, &block)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# Allows adding methods to a type by properly providing a module
|
97
|
+
# and adding it to the type
|
98
|
+
def type_extend_with_module(type, &block)
|
99
|
+
mod_name = :"#{type.to_s.classify}Methods"
|
100
|
+
mod = const_get(mod_name) if const_defined?(mod_name, false)
|
101
|
+
mod ||= const_set(mod_name, Module.new).tap do |m|
|
102
|
+
instance_variable_get("@#{type}")&.include(m)
|
103
|
+
end
|
104
|
+
|
105
|
+
mod.module_eval(&block)
|
106
|
+
end
|
107
|
+
|
80
108
|
end
|
81
109
|
end
|
82
110
|
end
|
data/lib/rails/graphql/uri.rb
CHANGED
data/lib/rails/graphql.rb
CHANGED
data/test/assets/sqlite.gql
CHANGED
@@ -171,6 +171,8 @@ input LiteFactionInput {
|
|
171
171
|
|
172
172
|
basesAttributes: [LiteBaseInput!]
|
173
173
|
|
174
|
+
greeting: String
|
175
|
+
|
174
176
|
name: String
|
175
177
|
|
176
178
|
shipsAttributes: [LiteShipInput!]
|
@@ -206,6 +208,8 @@ type LiteFaction {
|
|
206
208
|
|
207
209
|
bases: [LiteBase!]!
|
208
210
|
|
211
|
+
greeting: String
|
212
|
+
|
209
213
|
name: String
|
210
214
|
|
211
215
|
ships: [LiteShip!]!
|
data/test/config.rb
CHANGED
data/test/graphql/source_test.rb
CHANGED
@@ -129,6 +129,9 @@ class GraphQL_SourceTest < GraphQL::TestCase
|
|
129
129
|
end
|
130
130
|
|
131
131
|
def test_disable
|
132
|
+
# class_attribute changed and the stub does not work as expected
|
133
|
+
return skip if rails8?
|
134
|
+
|
132
135
|
described_class.stub(:hook_names, Set[:start]) do
|
133
136
|
assert_includes(described_class.hook_names, :start)
|
134
137
|
described_class.send(:disable, 'starts')
|
@@ -137,6 +140,9 @@ class GraphQL_SourceTest < GraphQL::TestCase
|
|
137
140
|
end
|
138
141
|
|
139
142
|
def test_enable
|
143
|
+
# class_attribute changed and the stub does not work as expected
|
144
|
+
return skip if rails8?
|
145
|
+
|
140
146
|
described_class.stub(:hook_names, Set[]) do
|
141
147
|
refute_includes(described_class.hook_names, :start)
|
142
148
|
described_class.send(:enable, 'starts')
|
@@ -157,4 +163,8 @@ class GraphQL_SourceTest < GraphQL::TestCase
|
|
157
163
|
def source_const
|
158
164
|
Rails::GraphQL::Source
|
159
165
|
end
|
166
|
+
|
167
|
+
def rails8?
|
168
|
+
ActiveSupport.gem_version >= Gem::Version.new('8')
|
169
|
+
end
|
160
170
|
end
|
@@ -132,6 +132,20 @@ class Integration_Memory_StarWarsQueryTest < GraphQL::IntegrationTestCase
|
|
132
132
|
GQL
|
133
133
|
end
|
134
134
|
|
135
|
+
def test_query_with_field_argument_and_default_value
|
136
|
+
argument = SCHEMA.find_type('Human')[:greeting].arguments[:name]
|
137
|
+
argument.stub_ivar(:@default, 'You') do
|
138
|
+
assert(argument.inspect, "name: String! = 'You'")
|
139
|
+
|
140
|
+
vader = { name: 'Han Solo', greeting: 'Hello You!' }
|
141
|
+
assert_result({ data: { human: vader } }, <<~GQL)
|
142
|
+
query WithFieldArgument {
|
143
|
+
human(id: "1002") { name greeting }
|
144
|
+
}
|
145
|
+
GQL
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
135
149
|
def test_query_with_fragment
|
136
150
|
luke = { name: 'Luke Skywalker', homePlanet: 'Tatooine' }
|
137
151
|
leia = { name: 'Leia Organa', homePlanet: 'Alderaan' }
|
@@ -27,8 +27,21 @@ class Integration_Memory_StarWarsValidationTest < GraphQL::IntegrationTestCase
|
|
27
27
|
locations: [{ line: 2, column: 1 }],
|
28
28
|
}]
|
29
29
|
|
30
|
-
assert_result(errors, <<~
|
30
|
+
assert_result(errors, <<~QUERY, dig: 'errors')
|
31
31
|
query DroidFieldInFragment { hero { name ... on Droid { primaryFunction
|
32
|
+
QUERY
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_fields_with_required_arguments
|
36
|
+
errors = [{
|
37
|
+
message: 'Invalid arguments for human field: the "id" argument can not be null.',
|
38
|
+
locations: [{ line: 1, column: 19 }, { line: 1, column: 33 }],
|
39
|
+
path: %w[HumanName human],
|
40
|
+
extensions: { stage: 'organize', exception: 'Rails::GraphQL::ArgumentsError' },
|
41
|
+
}]
|
42
|
+
|
43
|
+
assert_result(errors, <<~GQL, dig: 'errors')
|
44
|
+
query HumanName { human { name } }
|
32
45
|
GQL
|
33
46
|
end
|
34
47
|
|
@@ -6,7 +6,7 @@ class MySQLRecord < ActiveRecord::Base
|
|
6
6
|
establish_connection(
|
7
7
|
name: 'mysql',
|
8
8
|
adapter: 'mysql2',
|
9
|
-
host: ENV.fetch('GQL_MYSQL_HOST', '
|
9
|
+
host: ENV.fetch('GQL_MYSQL_HOST', '127.0.0.1'),
|
10
10
|
database: ENV.fetch('GQL_MYSQL_DATABASE', 'starwars'),
|
11
11
|
username: ENV.fetch('GQL_MYSQL_USERNAME', 'root'),
|
12
12
|
password: ENV['GQL_MYSQL_PASSWORD'],
|
@@ -14,6 +14,7 @@ end
|
|
14
14
|
SQLiteRecord.connection.instance_eval do
|
15
15
|
create_table 'lite_factions', force: :cascade do |t|
|
16
16
|
t.string 'name'
|
17
|
+
t.string 'greeting'
|
17
18
|
end
|
18
19
|
|
19
20
|
create_table 'lite_bases', force: :cascade do |t|
|
@@ -35,8 +36,8 @@ class LiteFaction < SQLiteRecord
|
|
35
36
|
accepts_nested_attributes_for :bases
|
36
37
|
accepts_nested_attributes_for :ships
|
37
38
|
|
38
|
-
REBELS = create!(name: 'Alliance to Restore the Republic')
|
39
|
-
EMPIRE = create!(name: 'Galactic Empire')
|
39
|
+
REBELS = create!(name: 'Alliance to Restore the Republic', greeting: 'Hello %s!')
|
40
|
+
EMPIRE = create!(name: 'Galactic Empire', greeting: 'Hi %s!')
|
40
41
|
end
|
41
42
|
|
42
43
|
class LiteBase < SQLiteRecord
|
@@ -79,6 +80,12 @@ class StartWarsSqliteSchema < GraphQL::Schema
|
|
79
80
|
with_options on: 'liteFactions' do
|
80
81
|
scoped_argument(:order) { |o| order(name: o) }
|
81
82
|
end
|
83
|
+
|
84
|
+
object_methods do
|
85
|
+
def greeting
|
86
|
+
format(current.greeting, 'you')
|
87
|
+
end
|
88
|
+
end
|
82
89
|
end
|
83
90
|
|
84
91
|
source LiteBase do
|
@@ -81,4 +81,11 @@ class Integration_SQLite_StarWarsQueryTest < GraphQL::IntegrationTestCase
|
|
81
81
|
query AllBases($order: String!) { liteBases(order: $order) { name } }
|
82
82
|
GQL
|
83
83
|
end
|
84
|
+
|
85
|
+
def test_query_methods_precedence
|
86
|
+
faction = { greeting: 'Hi you!' }
|
87
|
+
assert_result({ data: { liteFaction: faction } }, <<~GQL)
|
88
|
+
query EmpireFleet { liteFaction(id: "2") { greeting } }
|
89
|
+
GQL
|
90
|
+
end
|
84
91
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Silva
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -421,7 +421,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
421
421
|
- !ruby/object:Gem::Version
|
422
422
|
version: '0'
|
423
423
|
requirements: []
|
424
|
-
rubygems_version: 3.
|
424
|
+
rubygems_version: 3.4.19
|
425
425
|
signing_key:
|
426
426
|
specification_version: 4
|
427
427
|
summary: GraphQL meets RoR with the most Ruby-like DSL
|