rails-graphql 1.0.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ad5286d59309dafbc0ec0185c4b5c154bbccb7db15cfdb7831b78125212318c
4
- data.tar.gz: 797b52a24b9f9a38167846cc08bc0e50a8728b5bc85041df5d2b81d6208f22f4
3
+ metadata.gz: 5e7e0b35058deec4afd328520ed24fcd24fe4b0f8765b064b0ff0005398e9e7a
4
+ data.tar.gz: 0ef41b6819bbbe8057fa203ff6f008812e385030d3c171b401ac051a5890d756
5
5
  SHA512:
6
- metadata.gz: de92336e813d1b4e12b4399475c6ae7d7bb7eec21a59d33a8f8a7701f82a657575df19113d239e502a2ea642dce90c664433d2f7020367d4c735129eac41ab61
7
- data.tar.gz: 8739f94bf779f65df7db592641c31aad9493d6ed57ac104391341271af127a90c280de366857822fa73a1025b22bd6ddc8c98b2280baaa1e7832b86f622a93cc
6
+ metadata.gz: 14d030f7f42f0096d30d0fe9eab85baf3b52526ad5432620a16fa2288e6cfc5e0c123b8f433c78d1155a1dc0869ce5c7567bcdd3b6ff6eef5eca3de1d13ab399
7
+ data.tar.gz: 933ce0bcb53a39d436a1ff60056882d187bdcf4ec6a76b883f91724b550cdb81164a16e2bc91642db8e2093a76f3c20138ea8fa2ae92772e626352d3807f1adb
data/lib/gql_parser.so CHANGED
Binary file
@@ -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.
@@ -41,6 +41,10 @@ module Rails
41
41
  super || field.has_argument?(name)
42
42
  end
43
43
 
44
+ def has_arguments?
45
+ super || field.has_arguments?
46
+ end
47
+
44
48
  def arguments?
45
49
  super || field.arguments?
46
50
  end
@@ -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 < ActiveSupport::ProxyObject
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
@@ -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
- color(parts.compact.join(' '), MAGENTA, true)
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
- ActiveSupport::ParameterFilter.new(GraphQL.config.filter_parameters)
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.each.with_object({}) do |(name, value, var_name), hash|
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
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'uri/generic'
4
+
3
5
  module URI
4
6
  # URI::GLQ encodes objects from a GraphQL server as an URI.
5
7
  # It has the components:
@@ -14,7 +14,7 @@ module Rails
14
14
  module VERSION
15
15
  MAJOR = 1
16
16
  MINOR = 0
17
- TINY = 3
17
+ TINY = 5
18
18
  PRE = nil
19
19
 
20
20
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
data/lib/rails/graphql.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'i18n'
4
4
  require 'zlib'
5
+ require 'ostruct'
5
6
  require 'active_model'
6
7
  require 'active_support'
7
8
 
@@ -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
@@ -13,6 +13,7 @@ SimpleCov.start do
13
13
  add_group 'Source', ['/graphql/adapters', '/graphql/source']
14
14
  end
15
15
 
16
+ require 'logger'
16
17
  require 'minitest/autorun'
17
18
  require 'minitest/reporters'
18
19
  require 'active_record'
@@ -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, <<~GQL, dig: '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', 'localhost'),
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.3
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carlos Silva
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-24 00:00:00.000000000 Z
11
+ date: 2025-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -404,7 +404,7 @@ metadata:
404
404
  source_code_uri: https://github.com/virtualshield/rails-graphql
405
405
  bug_tracker_uri: https://github.com/virtualshield/rails-graphql/issues
406
406
  changelog_uri: https://github.com/virtualshield/rails-graphql/blob/master/CHANGELOG.md
407
- post_install_message:
407
+ post_install_message:
408
408
  rdoc_options:
409
409
  - "--title"
410
410
  - GraphQL server for Rails
@@ -421,8 +421,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
421
421
  - !ruby/object:Gem::Version
422
422
  version: '0'
423
423
  requirements: []
424
- rubygems_version: 3.3.26
425
- signing_key:
424
+ rubygems_version: 3.4.19
425
+ signing_key:
426
426
  specification_version: 4
427
427
  summary: GraphQL meets RoR with the most Ruby-like DSL
428
428
  test_files: