graphql_rails 1.0.0 → 1.1.0
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/.hound.yml +1 -0
- data/.rubocop.yml +3 -3
- data/.ruby-version +1 -1
- data/.travis.yml +2 -2
- data/CHANGELOG.md +3 -0
- data/Gemfile +3 -2
- data/Gemfile.lock +141 -117
- data/docs/README.md +2 -2
- data/docs/components/controller.md +21 -5
- data/docs/components/model.md +43 -3
- data/docs/index.html +1 -1
- data/graphql_rails.gemspec +5 -5
- data/lib/generators/graphql_rails/templates/graphql_router_spec.erb +10 -7
- data/lib/graphql_rails/attributes/attributable.rb +2 -4
- data/lib/graphql_rails/attributes/attribute.rb +26 -6
- data/lib/graphql_rails/attributes/attribute_name_parser.rb +1 -1
- data/lib/graphql_rails/attributes/input_attribute.rb +5 -1
- data/lib/graphql_rails/concerns/service.rb +6 -2
- data/lib/graphql_rails/controller.rb +6 -6
- data/lib/graphql_rails/controller/action.rb +5 -1
- data/lib/graphql_rails/controller/build_controller_action_resolver.rb +2 -2
- data/lib/graphql_rails/controller/request.rb +1 -1
- data/lib/graphql_rails/controller/request/format_errors.rb +1 -1
- data/lib/graphql_rails/model/add_fields_to_graphql_type.rb +45 -0
- data/lib/graphql_rails/model/build_graphql_input_type.rb +1 -1
- data/lib/graphql_rails/model/call_graphql_model_method.rb +14 -1
- data/lib/graphql_rails/model/configurable.rb +6 -2
- data/lib/graphql_rails/model/configuration.rb +9 -4
- data/lib/graphql_rails/model/find_or_build_graphql_type.rb +64 -0
- data/lib/graphql_rails/model/find_or_build_graphql_type_class.rb +46 -0
- data/lib/graphql_rails/router.rb +2 -2
- data/lib/graphql_rails/router/resource_routes_builder.rb +8 -8
- data/lib/graphql_rails/router/route.rb +3 -7
- data/lib/graphql_rails/router/schema_builder.rb +1 -1
- data/lib/graphql_rails/rspec_controller_helpers.rb +2 -2
- data/lib/graphql_rails/version.rb +1 -1
- metadata +21 -14
- data/lib/graphql_rails/model/build_graphql_type.rb +0 -53
data/docs/components/model.md
CHANGED
@@ -17,13 +17,13 @@ end
|
|
17
17
|
|
18
18
|
## graphql
|
19
19
|
|
20
|
-
This method must be called inside your model body. `
|
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
|
-
|
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 `
|
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:
|
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>
|
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">
|
data/graphql_rails.gemspec
CHANGED
@@ -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{
|
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.
|
23
|
+
spec.add_dependency 'graphql', '~> 1.11', '>= 1.11.6'
|
24
24
|
spec.add_dependency 'activesupport', '>= 4'
|
25
25
|
|
26
|
-
spec.add_development_dependency 'bundler', '~>
|
27
|
-
spec.add_development_dependency 'rake', '~>
|
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', '~>
|
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
|
-
|
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(
|
18
|
+
expect(to_definition).to eq(previous_definition)
|
16
19
|
end
|
17
20
|
end
|
18
21
|
end
|
@@ -13,14 +13,17 @@ module GraphqlRails
|
|
13
13
|
|
14
14
|
attr_reader :attributes
|
15
15
|
|
16
|
-
|
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
|
@@ -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
|
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?
|
@@ -7,8 +7,12 @@ module GraphqlRails
|
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
class_methods do
|
10
|
-
def call(*args, &block)
|
11
|
-
|
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)
|
@@ -19,13 +19,13 @@ module GraphqlRails
|
|
19
19
|
action = build_action
|
20
20
|
|
21
21
|
Class.new(ControllerActionResolver) do
|
22
|
-
type(*action.type_args)
|
22
|
+
type(*action.type_args, **action.type_options)
|
23
23
|
description(action.description)
|
24
24
|
controller(action.controller)
|
25
25
|
controller_action_name(action.name)
|
26
26
|
|
27
27
|
action.arguments.each do |attribute|
|
28
|
-
argument(*attribute.input_argument_args)
|
28
|
+
argument(*attribute.input_argument_args, **attribute.input_argument_options)
|
29
29
|
end
|
30
30
|
|
31
31
|
def self.inspect
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlRails
|
4
|
+
module Model
|
5
|
+
# Adds graphql attributes as graphql fields to given graphql schema object.
|
6
|
+
class AddFieldsToGraphqlType
|
7
|
+
require 'graphql_rails/concerns/service'
|
8
|
+
require 'graphql_rails/model/call_graphql_model_method'
|
9
|
+
|
10
|
+
include ::GraphqlRails::Service
|
11
|
+
|
12
|
+
def initialize(klass:, attributes:)
|
13
|
+
@klass = klass
|
14
|
+
@attributes = attributes
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
attributes.each { |attribute| define_graphql_field(attribute) }
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :attributes, :klass
|
24
|
+
|
25
|
+
def define_graphql_field(attribute) # rubocop:disable Metrics/MethodLength)
|
26
|
+
klass.class_eval do
|
27
|
+
field(*attribute.field_args, **attribute.field_options) do
|
28
|
+
attribute.attributes.values.each do |arg_attribute|
|
29
|
+
argument(*arg_attribute.input_argument_args, **arg_attribute.input_argument_options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
define_method(attribute.field_name) do |**kwargs|
|
34
|
+
CallGraphqlModelMethod.call(
|
35
|
+
model: object,
|
36
|
+
attribute_config: attribute,
|
37
|
+
method_keyword_arguments: kwargs,
|
38
|
+
graphql_context: context
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -24,7 +24,7 @@ module GraphqlRails
|
|
24
24
|
description(type_description)
|
25
25
|
|
26
26
|
type_attributes.each_value do |type_attribute|
|
27
|
-
argument(*type_attribute.input_argument_args)
|
27
|
+
argument(*type_attribute.input_argument_args, **type_attribute.input_argument_options)
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.inspect
|
@@ -31,10 +31,23 @@ module GraphqlRails
|
|
31
31
|
if custom_keyword_arguments.empty?
|
32
32
|
model.send(method_name)
|
33
33
|
else
|
34
|
-
|
34
|
+
formatted_arguments = formatted_method_input(custom_keyword_arguments)
|
35
|
+
model.send(method_name, **formatted_arguments)
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
39
|
+
def formatted_method_input(keyword_arguments)
|
40
|
+
keyword_arguments.transform_values do |input_argument|
|
41
|
+
formatted_method_input_argument(input_argument)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def formatted_method_input_argument(argument)
|
46
|
+
return argument.to_h if argument.is_a?(GraphQL::Schema::InputObject)
|
47
|
+
|
48
|
+
argument
|
49
|
+
end
|
50
|
+
|
38
51
|
def method_name
|
39
52
|
attribute_config.property
|
40
53
|
end
|
@@ -9,11 +9,15 @@ module GraphqlRails
|
|
9
9
|
@attributes ||= {}
|
10
10
|
end
|
11
11
|
|
12
|
-
def name(
|
13
|
-
@name =
|
12
|
+
def name(graphql_name = nil)
|
13
|
+
@name = graphql_name if graphql_name
|
14
14
|
@name || default_name
|
15
15
|
end
|
16
16
|
|
17
|
+
def type_name
|
18
|
+
@type_name ||= "#{name.camelize}Type#{SecureRandom.hex}"
|
19
|
+
end
|
20
|
+
|
17
21
|
def description(new_description = nil)
|
18
22
|
@description = new_description if new_description
|
19
23
|
@description
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'graphql_rails/attributes'
|
4
|
-
require 'graphql_rails/model/
|
4
|
+
require 'graphql_rails/model/find_or_build_graphql_type'
|
5
5
|
require 'graphql_rails/model/build_enum_type'
|
6
6
|
require 'graphql_rails/model/input'
|
7
7
|
require 'graphql_rails/model/configurable'
|
@@ -32,7 +32,9 @@ module GraphqlRails
|
|
32
32
|
|
33
33
|
attributes[key].tap do |attribute|
|
34
34
|
attribute_options.each do |method_name, args|
|
35
|
-
|
35
|
+
send_args = [method_name]
|
36
|
+
send_args << args if attribute.method(method_name).parameters.present?
|
37
|
+
attribute.public_send(*send_args)
|
36
38
|
end
|
37
39
|
|
38
40
|
yield(attribute) if block_given?
|
@@ -54,8 +56,11 @@ module GraphqlRails
|
|
54
56
|
end
|
55
57
|
|
56
58
|
def graphql_type
|
57
|
-
@graphql_type ||=
|
58
|
-
name: name,
|
59
|
+
@graphql_type ||= FindOrBuildGraphqlType.call(
|
60
|
+
name: name,
|
61
|
+
description: description,
|
62
|
+
attributes: attributes,
|
63
|
+
type_name: type_name
|
59
64
|
)
|
60
65
|
end
|
61
66
|
|