graphql_rails 1.0.0 → 1.2.3

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +1 -0
  3. data/.rubocop.yml +3 -3
  4. data/.ruby-version +1 -1
  5. data/.travis.yml +2 -2
  6. data/CHANGELOG.md +22 -0
  7. data/Gemfile +3 -2
  8. data/Gemfile.lock +145 -119
  9. data/docs/README.md +3 -3
  10. data/docs/components/controller.md +23 -7
  11. data/docs/components/model.md +43 -3
  12. data/docs/getting_started/quick_start.md +1 -1
  13. data/docs/index.html +1 -1
  14. data/docs/other_tools/query_runner.md +1 -1
  15. data/docs/other_tools/schema_dump.md +1 -1
  16. data/graphql_rails.gemspec +5 -5
  17. data/lib/generators/graphql_rails/templates/graphql_router_spec.erb +10 -7
  18. data/lib/graphql_rails/attributes/attributable.rb +5 -9
  19. data/lib/graphql_rails/attributes/attribute.rb +26 -6
  20. data/lib/graphql_rails/attributes/attribute_name_parser.rb +4 -4
  21. data/lib/graphql_rails/attributes/input_attribute.rb +5 -1
  22. data/lib/graphql_rails/attributes/type_parseable.rb +17 -13
  23. data/lib/graphql_rails/concerns/service.rb +6 -2
  24. data/lib/graphql_rails/controller.rb +6 -6
  25. data/lib/graphql_rails/controller/action.rb +5 -1
  26. data/lib/graphql_rails/controller/build_controller_action_resolver.rb +2 -2
  27. data/lib/graphql_rails/controller/log_controller_action.rb +7 -2
  28. data/lib/graphql_rails/controller/request.rb +1 -1
  29. data/lib/graphql_rails/controller/request/format_errors.rb +1 -1
  30. data/lib/graphql_rails/decorator/relation_decorator.rb +0 -4
  31. data/lib/graphql_rails/model/add_fields_to_graphql_type.rb +45 -0
  32. data/lib/graphql_rails/model/build_connection_type.rb +5 -1
  33. data/lib/graphql_rails/model/build_connection_type/count_items.rb +2 -2
  34. data/lib/graphql_rails/model/build_graphql_input_type.rb +1 -1
  35. data/lib/graphql_rails/model/call_graphql_model_method.rb +14 -1
  36. data/lib/graphql_rails/model/configurable.rb +6 -2
  37. data/lib/graphql_rails/model/configuration.rb +9 -4
  38. data/lib/graphql_rails/model/find_or_build_graphql_type.rb +64 -0
  39. data/lib/graphql_rails/model/find_or_build_graphql_type_class.rb +46 -0
  40. data/lib/graphql_rails/router.rb +2 -2
  41. data/lib/graphql_rails/router/resource_routes_builder.rb +8 -8
  42. data/lib/graphql_rails/router/route.rb +3 -7
  43. data/lib/graphql_rails/router/schema_builder.rb +5 -1
  44. data/lib/graphql_rails/rspec_controller_helpers.rb +2 -2
  45. data/lib/graphql_rails/version.rb +1 -1
  46. metadata +25 -18
  47. data/lib/graphql_rails/model/build_graphql_type.rb +0 -53
@@ -78,7 +78,7 @@ Specifies input type:
78
78
  class OrderController < GraphqlRails::Controller
79
79
  action(:create)
80
80
  .permit_input(:price, type: :integer!)
81
- # Same as `.permit(amount: :integer!)`
81
+ # Same as `.permit(price: :integer!)`
82
82
  end
83
83
  ```
84
84
 
@@ -169,7 +169,7 @@ class UsersController < GraphqlRails::Controller
169
169
  end
170
170
  ```
171
171
 
172
- Also check ['decorating controller responses']('components/decorator') for more details about working with active record and decorators.
172
+ Also check ['decorating controller responses'](components/decorator) for more details about working with active record and decorators.
173
173
 
174
174
  #### *max_page_size*
175
175
 
@@ -219,6 +219,22 @@ class UsersController < GraphqlRails::Controller
219
219
  end
220
220
  ```
221
221
 
222
+ You can also return raw graphql-ruby types:
223
+
224
+ ```ruby
225
+ # raw graphql-ruby type:
226
+ class OrderType < GraphQL::Schema::Object
227
+ graphql_name 'Order'
228
+ field :id, ID
229
+ end
230
+
231
+ class UsersController < GraphqlRails::Controller
232
+ action(:last_order).permit(:id).returns(OrderType)
233
+ end
234
+ ```
235
+
236
+ Check [graphql-ruby documentation](https://graphql-ruby.org) for more details about graphql-ruby types.
237
+
222
238
  ### *returns_list*
223
239
 
224
240
  When you have defined `model` dynamically, you can use `returns_list` to indicate that action must return list without specifying model type for each action. By default list and inner types are required but you can change that with `required_list: false` and `required_inner: false`
@@ -430,7 +446,7 @@ class UsersController < GraphqlRails::Controller
430
446
  raise 'Not authenticated' unless User.where(token: params[:token]).exist?
431
447
  end
432
448
 
433
- def require_auth_token
449
+ def require_admin_token
434
450
  raise 'Admin not authenticated' unless Admin.where(token: params[:admin_token]).exist?
435
451
  end
436
452
  end
@@ -438,13 +454,13 @@ end
438
454
 
439
455
  ## decorating objects
440
456
 
441
- See ['Decorating controller responses']('components/decorator') for various options how you can decorate paginated responses
457
+ See ['Decorating controller responses'](components/decorator) for various options how you can decorate paginated responses
442
458
 
443
459
  ## Rendering errors
444
460
 
445
461
  ### Rendering strings as errors
446
462
 
447
- The simples way to render error is to provide list of error messages, like this:
463
+ The simplest way to render an error is to provide a list of error messages, like this:
448
464
 
449
465
  ```ruby
450
466
  class UsersController < GraphqlRails::Controller
@@ -509,12 +525,12 @@ end
509
525
 
510
526
  ### Raising custom error classes
511
527
 
512
- If you want to have customized error classes you need to create errors which inherits from `GraphqlRails::ExecutionError`
528
+ If you want to have customized error classes you need to create errors which inherit from `GraphqlRails::ExecutionError`
513
529
 
514
530
  ```ruby
515
531
  class MyCustomError < GraphqlRails::ExecutionError
516
532
  def to_h
517
- # this part will be rendered in graphl
533
+ # this part will be rendered in graphql
518
534
  { something_custom: 'yes' }
519
535
  end
520
536
  end
@@ -17,13 +17,13 @@ end
17
17
 
18
18
  ## graphql
19
19
 
20
- This method must be called inside your model body. `grapqhl` is used for making your model convertible to graphql type.
20
+ This method must be called inside your model body. `graphql` is used for making your model convertible to graphql type.
21
21
 
22
22
  ## attribute
23
23
 
24
24
  Most commonly you will use `attribute` to make your model methods and attributes visible via graphql endpoint.
25
25
 
26
- ## attribute.type
26
+ ### attribute.type
27
27
 
28
28
  Some types can be determined by attribute name, so you can skip this attribute:
29
29
 
@@ -54,9 +54,33 @@ class User
54
54
  end
55
55
  ```
56
56
 
57
+ #### attribute.type: using graphql-ruby objects
58
+
59
+ You can also use raw graphql-ruby objects as attribute types. Here is an example:
60
+
61
+ ```ruby
62
+ # raw graphql-ruby type:
63
+ class AddressType < GraphQL::Schema::Object
64
+ graphql_name 'Address'
65
+
66
+ field :city, String, null: false
67
+ field :street_name, String, null: false
68
+ field :street_number, Integer
69
+ end
70
+
71
+ # GraphqlRails model:
72
+ class User
73
+ include GraphqlRails::Model
74
+
75
+ graphql.attribute :address, type: AddressType, required: true
76
+ end
77
+ ```
78
+
79
+ Check [graphql-ruby documentation](https://graphql-ruby.org) for more details about graphql-ruby types.
80
+
57
81
  ### attribute.property
58
82
 
59
- By default graphql attribute names are expected to be same as model methods/attributes, but if you want to use different name on grapqhl side, you can use `propery` option:
83
+ By default graphql attribute names are expected to be same as model methods/attributes, but if you want to use different name on grapqhl side, you can use `property` option:
60
84
 
61
85
  ```ruby
62
86
  class User
@@ -86,6 +110,22 @@ class User
86
110
  end
87
111
  ```
88
112
 
113
+ ### attribute.options
114
+
115
+ Allows passing options to attribute definition. Available options:
116
+
117
+ * `attribute_name_format` - if `:original` value is passed, it will not camelCase attribute name.
118
+
119
+ ```ruby
120
+ class User
121
+ include GraphqlRails::Model
122
+
123
+ graphql do |c|
124
+ c.attribute :first_name # will be accessible as firstName from client side
125
+ c.attribute :first_name, options: { attribute_name_format: :original } # will be accessible as first_name from client side
126
+ end
127
+ end
128
+
89
129
  ### attribute.permit
90
130
 
91
131
  To define attributes which are accepted by each model method, you need to call `permit` method, like this:
@@ -11,7 +11,7 @@ bundle exec rails g graphql_rails:install
11
11
  ```ruby
12
12
  # config/graphql/routes.rb
13
13
  GraphqlRails::Router.draw do
14
- # will create createUser, updateUser, deleteUser mutations and user, users queries.
14
+ # will create createUser, updateUser, destroyUser mutations and user, users queries.
15
15
  # expects that UsersController class exist
16
16
  resources :users
17
17
 
data/docs/index.html CHANGED
@@ -2,7 +2,7 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
- <title>Document</title>
5
+ <title>GraphqlRails</title>
6
6
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
7
7
  <meta name="description" content="Description">
8
8
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
@@ -16,7 +16,7 @@ end
16
16
 
17
17
  ## Executing grouped schema
18
18
 
19
- If you have multiple schemas (read [routes section]((components/routes) on how to do that) and you want to render group specific schema, you need to provide group name, like this:
19
+ If you have multiple schemas (read [routes section](components/routes) on how to do that) and you want to render group specific schema, you need to provide group name, like this:
20
20
 
21
21
  ```ruby
22
22
  class MyRailsClass < ApplicationController
@@ -8,7 +8,7 @@ rake graphql_rails:schema:dump
8
8
 
9
9
  ## Dumping non default schema
10
10
 
11
- You can have multiple graphql schemas. Read more about this in [routes section]((components/routes). In order to generate schema for one of groups, provide optional `name` argument:
11
+ You can have multiple graphql schemas. Read more about this in [routes section](components/routes). In order to generate schema for one of groups, provide optional `name` argument:
12
12
 
13
13
  ```bash
14
14
  rake graphql_rails:schema:dump['your_group_name']
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ['Povilas Jurčys']
10
10
  spec.email = ['po.jurcys@gmail.com']
11
11
 
12
- spec.summary = %q{GraphQL server and client for rails}
12
+ spec.summary = %q{Rails style structure for GraphQL API.}
13
13
  spec.homepage = 'https://github.com/samesystem/graphql_rails'
14
14
  spec.license = 'MIT'
15
15
 
@@ -20,13 +20,13 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ['lib']
22
22
 
23
- spec.add_dependency 'graphql', '>= 1.9.12'
23
+ spec.add_dependency 'graphql', '~> 1.12', '>= 1.12.4'
24
24
  spec.add_dependency 'activesupport', '>= 4'
25
25
 
26
- spec.add_development_dependency 'bundler', '~> 1.16'
27
- spec.add_development_dependency 'rake', '~> 10.0'
26
+ spec.add_development_dependency 'bundler', '~> 2'
27
+ spec.add_development_dependency 'rake', '~> 13.0'
28
28
  spec.add_development_dependency 'rspec', '~> 3.0'
29
29
  spec.add_development_dependency 'activerecord'
30
30
  spec.add_development_dependency 'pry-byebug'
31
- spec.add_development_dependency 'rails', '~> 5'
31
+ spec.add_development_dependency 'rails', '~> 6'
32
32
  end
@@ -3,16 +3,19 @@
3
3
  require 'rails_helper'
4
4
 
5
5
  RSpec.describe GraphqlRouter do
6
- describe '#execute' do
6
+ subject(:schema) { described_class.graphql_schema }
7
+
8
+ describe '#to_definition' do
9
+ subject(:to_definition) { schema.to_definition.strip }
10
+
11
+ let(:schema_dump_path) { Rails.root.join('spec', 'fixtures', 'graphql_schema.graphql') }
12
+ let(:previous_definition) { File.read(schema_dump_path).strip }
13
+
7
14
  it 'returns correct structure' do
8
15
  # if you need to update saved_schema, run rake task:
9
- # $ RAILS_ENV=test rake graphql_rails:schema:dump
10
-
11
- schema_path = Rails.root.join('spec', 'fixtures', 'graphql_schema.graphql')
12
- saved_schema = File.read(schema_path).strip
13
- real_schema = described_class.to_definition.strip
16
+ # $ RAILS_ENV=test bin/rake graphql_rails:schema:dump
14
17
 
15
- expect(real_schema).to eq(saved_schema)
18
+ expect(to_definition).to eq(previous_definition)
16
19
  end
17
20
  end
18
21
  end
@@ -21,11 +21,9 @@ module GraphqlRails
21
21
  end
22
22
 
23
23
  def required?
24
- if @required.nil?
25
- attribute_name_parser.required? || !initial_type.to_s[/!$/].nil?
26
- else
27
- @required
28
- end
24
+ return @required unless @required.nil?
25
+
26
+ attribute_name_parser.required? || !initial_type.to_s[/!$/].nil? || initial_type.is_a?(GraphQL::Schema::NonNull)
29
27
  end
30
28
 
31
29
  def required
@@ -46,10 +44,8 @@ module GraphqlRails
46
44
  !required?
47
45
  end
48
46
 
49
- protected
50
-
51
- def options
52
- {}
47
+ def scalar_type?
48
+ type_parser.raw_graphql_type? || type_parser.core_scalar_type?
53
49
  end
54
50
 
55
51
  private
@@ -13,14 +13,17 @@ module GraphqlRails
13
13
 
14
14
  attr_reader :attributes
15
15
 
16
- def initialize(name, type = nil, description: nil, property: name, required: nil)
16
+ # rubocop:disable Metrics/ParameterLists
17
+ def initialize(name, type = nil, description: nil, property: name, required: nil, options: {})
17
18
  @initial_type = type
18
19
  @initial_name = name
20
+ @options = options
19
21
  @description = description
20
22
  @property = property.to_s
21
23
  @required = required
22
24
  @attributes ||= {}
23
25
  end
26
+ # rubocop:enable Metrics/ParameterLists
24
27
 
25
28
  def type(new_type = nil)
26
29
  return @initial_type if new_type.nil?
@@ -43,18 +46,29 @@ module GraphqlRails
43
46
  self
44
47
  end
45
48
 
49
+ def options(new_options = {})
50
+ return @options if new_options.blank?
51
+
52
+ @options = new_options
53
+ self
54
+ end
55
+
46
56
  def field_args
47
57
  [
48
58
  field_name,
49
59
  type_parser.type_arg,
50
- *description,
51
- {
52
- method: property.to_sym,
53
- null: optional?
54
- }
60
+ *description
55
61
  ]
56
62
  end
57
63
 
64
+ def field_options
65
+ {
66
+ method: property.to_sym,
67
+ null: optional?,
68
+ camelize: camelize?
69
+ }
70
+ end
71
+
58
72
  def argument_args
59
73
  [
60
74
  field_name,
@@ -69,6 +83,12 @@ module GraphqlRails
69
83
  protected
70
84
 
71
85
  attr_reader :initial_type, :initial_name
86
+
87
+ private
88
+
89
+ def camelize?
90
+ options[:input_format] != :original && options[:attribute_name_format] != :original
91
+ end
72
92
  end
73
93
  end
74
94
  end
@@ -27,11 +27,11 @@ module GraphqlRails
27
27
  @graphql_type ||= \
28
28
  case name
29
29
  when 'id', /_id\Z/
30
- GraphQL::ID_TYPE
30
+ GraphQL::Types::ID
31
31
  when /\?\Z/
32
- GraphQL::BOOLEAN_TYPE
32
+ GraphQL::Types::Boolean
33
33
  else
34
- GraphQL::STRING_TYPE
34
+ GraphQL::Types::String
35
35
  end
36
36
  end
37
37
 
@@ -44,7 +44,7 @@ module GraphqlRails
44
44
  attr_reader :options
45
45
 
46
46
  def original_format?
47
- options[:input_format] == :original
47
+ options[:input_format] == :original || options[:attribute_name_format] == :original
48
48
  end
49
49
 
50
50
  def preprocesed_name
@@ -24,7 +24,11 @@ module GraphqlRails
24
24
  def input_argument_args
25
25
  type = raw_input_type || input_type_parser.input_type_arg
26
26
 
27
- [field_name, type, { required: required?, description: description, camelize: false }]
27
+ [field_name, type]
28
+ end
29
+
30
+ def input_argument_options
31
+ { required: required?, description: description, camelize: false }
28
32
  end
29
33
 
30
34
  def paginated?
@@ -11,23 +11,23 @@ module GraphqlRails
11
11
  class UnknownTypeError < ArgumentError; end
12
12
 
13
13
  TYPE_MAPPING = {
14
- 'id' => GraphQL::ID_TYPE,
14
+ 'id' => GraphQL::Types::ID,
15
15
 
16
- 'int' => GraphQL::INT_TYPE,
17
- 'integer' => GraphQL::INT_TYPE,
16
+ 'int' => GraphQL::Types::Int,
17
+ 'integer' => GraphQL::Types::Int,
18
18
 
19
- 'string' => GraphQL::STRING_TYPE,
20
- 'str' => GraphQL::STRING_TYPE,
21
- 'text' => GraphQL::STRING_TYPE,
22
- 'time' => GraphQL::STRING_TYPE,
23
- 'date' => GraphQL::STRING_TYPE,
19
+ 'string' => GraphQL::Types::String,
20
+ 'str' => GraphQL::Types::String,
21
+ 'text' => GraphQL::Types::String,
22
+ 'time' => GraphQL::Types::String,
23
+ 'date' => GraphQL::Types::String,
24
24
 
25
- 'bool' => GraphQL::BOOLEAN_TYPE,
26
- 'boolean' => GraphQL::BOOLEAN_TYPE,
25
+ 'bool' => GraphQL::Types::Boolean,
26
+ 'boolean' => GraphQL::Types::Boolean,
27
27
 
28
- 'float' => GraphQL::FLOAT_TYPE,
29
- 'double' => GraphQL::FLOAT_TYPE,
30
- 'decimal' => GraphQL::FLOAT_TYPE
28
+ 'float' => GraphQL::Types::Float,
29
+ 'double' => GraphQL::Types::Float,
30
+ 'decimal' => GraphQL::Types::Float
31
31
  }.freeze
32
32
 
33
33
  WRAPPER_TYPES = [
@@ -57,6 +57,10 @@ module GraphqlRails
57
57
  unparsed_type < GraphQL::Schema::Member
58
58
  end
59
59
 
60
+ def core_scalar_type?
61
+ unwrapped_scalar_type.in?(TYPE_MAPPING.values)
62
+ end
63
+
60
64
  def graphql_model
61
65
  type_class = \
62
66
  if unparsed_type.is_a?(Class) && unparsed_type < GraphqlRails::Model
@@ -7,8 +7,12 @@ module GraphqlRails
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  class_methods do
10
- def call(*args, &block)
11
- new(*args).call(&block)
10
+ def call(*args, **kwargs, &block)
11
+ if kwargs.present?
12
+ new(*args, **kwargs).call(&block)
13
+ else
14
+ new(*args).call(&block)
15
+ end
12
16
  end
13
17
  end
14
18
  end
@@ -18,16 +18,16 @@ module GraphqlRails
18
18
  subclass.instance_variable_set(:@controller_configuration, new_config)
19
19
  end
20
20
 
21
- def before_action(*args, &block)
22
- controller_configuration.add_action_hook(:before, *args, &block)
21
+ def before_action(*args, **kwargs, &block)
22
+ controller_configuration.add_action_hook(:before, *args, **kwargs, &block)
23
23
  end
24
24
 
25
- def around_action(*args, &block)
26
- controller_configuration.add_action_hook(:around, *args, &block)
25
+ def around_action(*args, **kwargs, &block)
26
+ controller_configuration.add_action_hook(:around, *args, **kwargs, &block)
27
27
  end
28
28
 
29
- def after_action(*args, &block)
30
- controller_configuration.add_action_hook(:after, *args, &block)
29
+ def after_action(*args, **kwargs, &block)
30
+ controller_configuration.add_action_hook(:after, *args, **kwargs, &block)
31
31
  end
32
32
 
33
33
  def action(action_name)