graphql_rails 0.8.0 → 1.2.2
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 +31 -0
- data/Gemfile +3 -2
- data/Gemfile.lock +147 -124
- data/docs/README.md +24 -8
- data/docs/_sidebar.md +3 -0
- data/docs/components/controller.md +194 -21
- data/docs/components/model.md +193 -5
- data/docs/components/routes.md +28 -0
- data/docs/getting_started/quick_start.md +10 -3
- data/docs/index.html +1 -1
- data/docs/other_tools/query_runner.md +49 -0
- data/docs/other_tools/schema_dump.md +29 -0
- data/docs/testing/testing.md +3 -1
- data/graphql_rails.gemspec +5 -5
- data/lib/generators/graphql_rails/install_generator.rb +50 -0
- data/lib/generators/graphql_rails/templates/example_users_controller.erb +19 -0
- data/lib/generators/graphql_rails/templates/graphql_application_controller.erb +8 -0
- data/lib/generators/graphql_rails/templates/graphql_controller.erb +20 -0
- data/lib/generators/graphql_rails/templates/graphql_router.erb +19 -0
- data/lib/generators/graphql_rails/templates/graphql_router_spec.erb +21 -0
- data/lib/graphql_rails.rb +2 -0
- data/lib/graphql_rails/attributes/attributable.rb +20 -21
- data/lib/graphql_rails/attributes/attribute.rb +41 -4
- data/lib/graphql_rails/attributes/attribute_name_parser.rb +4 -4
- data/lib/graphql_rails/attributes/input_attribute.rb +24 -10
- data/lib/graphql_rails/attributes/input_type_parser.rb +24 -46
- data/lib/graphql_rails/attributes/type_parseable.rb +132 -0
- data/lib/graphql_rails/attributes/type_parser.rb +58 -54
- data/lib/graphql_rails/concerns/service.rb +19 -0
- data/lib/graphql_rails/controller.rb +26 -22
- data/lib/graphql_rails/controller/action.rb +12 -67
- data/lib/graphql_rails/controller/action_configuration.rb +70 -34
- data/lib/graphql_rails/controller/build_controller_action_resolver.rb +52 -0
- data/lib/graphql_rails/controller/build_controller_action_resolver/controller_action_resolver.rb +28 -0
- data/lib/graphql_rails/controller/configuration.rb +56 -5
- data/lib/graphql_rails/controller/log_controller_action.rb +11 -6
- data/lib/graphql_rails/controller/request.rb +29 -8
- data/lib/graphql_rails/controller/request/format_errors.rb +58 -0
- data/lib/graphql_rails/decorator/relation_decorator.rb +1 -5
- data/lib/graphql_rails/errors/custom_execution_error.rb +22 -0
- data/lib/graphql_rails/errors/execution_error.rb +6 -7
- data/lib/graphql_rails/errors/system_error.rb +14 -0
- data/lib/graphql_rails/errors/validation_error.rb +1 -5
- data/lib/graphql_rails/input_configurable.rb +47 -0
- data/lib/graphql_rails/model.rb +19 -4
- data/lib/graphql_rails/model/add_fields_to_graphql_type.rb +45 -0
- data/lib/graphql_rails/model/build_connection_type.rb +52 -0
- data/lib/graphql_rails/model/{configuration → build_connection_type}/count_items.rb +5 -5
- data/lib/graphql_rails/model/build_enum_type.rb +39 -10
- data/lib/graphql_rails/model/build_graphql_input_type.rb +8 -4
- data/lib/graphql_rails/model/call_graphql_model_method.rb +72 -0
- data/lib/graphql_rails/model/configurable.rb +6 -2
- data/lib/graphql_rails/model/configuration.rb +11 -10
- 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/model/input.rb +10 -6
- data/lib/graphql_rails/query_runner.rb +68 -0
- data/lib/graphql_rails/railtie.rb +10 -0
- data/lib/graphql_rails/router.rb +40 -13
- data/lib/graphql_rails/router/resource_routes_builder.rb +10 -9
- data/lib/graphql_rails/router/route.rb +21 -6
- data/lib/graphql_rails/router/schema_builder.rb +30 -11
- data/lib/graphql_rails/rspec_controller_helpers.rb +6 -4
- data/lib/graphql_rails/tasks/dump_graphql_schema.rb +57 -0
- data/lib/graphql_rails/tasks/schema.rake +14 -0
- data/lib/graphql_rails/version.rb +1 -1
- metadata +48 -21
- data/lib/graphql_rails/controller/controller_function.rb +0 -50
- data/lib/graphql_rails/controller/format_results.rb +0 -36
- data/lib/graphql_rails/model/build_graphql_type.rb +0 -37
@@ -27,11 +27,11 @@ module GraphqlRails
|
|
27
27
|
@graphql_type ||= \
|
28
28
|
case name
|
29
29
|
when 'id', /_id\Z/
|
30
|
-
GraphQL::
|
30
|
+
GraphQL::Types::ID
|
31
31
|
when /\?\Z/
|
32
|
-
GraphQL::
|
32
|
+
GraphQL::Types::Boolean
|
33
33
|
else
|
34
|
-
GraphQL::
|
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
|
@@ -5,12 +5,13 @@ module GraphqlRails
|
|
5
5
|
# contains info about single graphql input attribute
|
6
6
|
class InputAttribute
|
7
7
|
require_relative './input_type_parser'
|
8
|
+
require_relative './attribute_name_parser'
|
8
9
|
include Attributable
|
9
10
|
|
10
11
|
attr_reader :description
|
11
12
|
|
12
13
|
# rubocop:disable Metrics/ParameterLists
|
13
|
-
def initialize(name, type
|
14
|
+
def initialize(name, type: nil, description: nil, subtype: nil, required: nil, options: {})
|
14
15
|
@initial_name = name
|
15
16
|
@initial_type = type
|
16
17
|
@description = description
|
@@ -20,26 +21,39 @@ module GraphqlRails
|
|
20
21
|
end
|
21
22
|
# rubocop:enable Metrics/ParameterLists
|
22
23
|
|
23
|
-
def function_argument_args
|
24
|
-
[field_name, graphql_input_type, { description: description }]
|
25
|
-
end
|
26
|
-
|
27
24
|
def input_argument_args
|
28
|
-
type = raw_input_type || input_type_parser.
|
25
|
+
type = raw_input_type || input_type_parser.input_type_arg
|
26
|
+
|
27
|
+
[field_name, type]
|
28
|
+
end
|
29
29
|
|
30
|
-
|
30
|
+
def input_argument_options
|
31
|
+
{ required: required?, description: description, camelize: false }
|
31
32
|
end
|
32
33
|
|
33
|
-
def
|
34
|
-
|
34
|
+
def paginated?
|
35
|
+
false
|
35
36
|
end
|
36
37
|
|
37
38
|
private
|
38
39
|
|
39
40
|
attr_reader :initial_name, :initial_type, :options, :subtype
|
40
41
|
|
42
|
+
def attribute_name_parser
|
43
|
+
@attribute_name_parser ||= AttributeNameParser.new(
|
44
|
+
initial_name, options: attribute_naming_options
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def attribute_naming_options
|
49
|
+
options.slice(:input_format)
|
50
|
+
end
|
51
|
+
|
41
52
|
def input_type_parser
|
42
|
-
@input_type_parser ||=
|
53
|
+
@input_type_parser ||= begin
|
54
|
+
initial_parseable_type = initial_type || attribute_name_parser.graphql_type
|
55
|
+
InputTypeParser.new(initial_parseable_type, subtype: subtype)
|
56
|
+
end
|
43
57
|
end
|
44
58
|
|
45
59
|
def raw_input_type
|
@@ -5,9 +5,13 @@ require 'graphql'
|
|
5
5
|
module GraphqlRails
|
6
6
|
module Attributes
|
7
7
|
# converts string value in to GraphQL type
|
8
|
-
class InputTypeParser
|
8
|
+
class InputTypeParser
|
9
|
+
require_relative './type_parseable'
|
10
|
+
|
11
|
+
include TypeParseable
|
12
|
+
|
9
13
|
def initialize(unparsed_type, subtype:)
|
10
|
-
|
14
|
+
@unparsed_type = unparsed_type
|
11
15
|
@subtype = subtype
|
12
16
|
end
|
13
17
|
|
@@ -17,68 +21,42 @@ module GraphqlRails
|
|
17
21
|
partly_parsed_type || parsed_type
|
18
22
|
end
|
19
23
|
|
20
|
-
def
|
21
|
-
return nil if unparsed_type.nil?
|
22
|
-
|
23
|
-
partly_parsed_type || parsed_nullable_type
|
24
|
-
end
|
25
|
-
|
26
|
-
protected
|
27
|
-
|
28
|
-
def partly_parsed_type
|
29
|
-
return unparsed_type if raw_graphql_type?
|
30
|
-
return unparsed_type.graphql_input_type if unparsed_type.is_a?(GraphqlRails::Model::Input)
|
31
|
-
end
|
32
|
-
|
33
|
-
def parsed_nullable_type
|
34
|
-
if list?
|
35
|
-
parsed_inner_type.to_list_type
|
36
|
-
else
|
37
|
-
type_by_name
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def parsed_type
|
24
|
+
def input_type_arg
|
42
25
|
if list?
|
43
|
-
|
26
|
+
list_type_arg
|
44
27
|
else
|
45
|
-
|
28
|
+
unwrapped_type
|
46
29
|
end
|
47
30
|
end
|
48
31
|
|
49
|
-
|
50
|
-
unparsed_type.is_a?(GraphQL::InputObjectType) || super
|
51
|
-
end
|
32
|
+
private
|
52
33
|
|
53
|
-
|
54
|
-
type_class = graphql_model
|
55
|
-
return unless type_class
|
34
|
+
attr_reader :unparsed_type, :subtype
|
56
35
|
|
57
|
-
|
36
|
+
def unwrapped_type
|
37
|
+
raw_unwrapped_type || unwrapped_scalar_type || unwrapped_model_input_type || raise_not_supported_type_error
|
58
38
|
end
|
59
39
|
|
60
|
-
def
|
61
|
-
|
40
|
+
def raw_unwrapped_type
|
41
|
+
return nil unless raw_graphql_type?
|
62
42
|
|
63
|
-
|
64
|
-
list_type = list_type.to_graphql if list_type.respond_to?(:to_graphql)
|
65
|
-
list_type.to_non_null_type
|
66
|
-
else
|
67
|
-
list_type
|
68
|
-
end
|
43
|
+
unwrap_type(unparsed_type)
|
69
44
|
end
|
70
45
|
|
71
|
-
def
|
46
|
+
def list_type_arg
|
72
47
|
if required_inner_type?
|
73
|
-
|
48
|
+
[unwrapped_type]
|
74
49
|
else
|
75
|
-
|
50
|
+
[unwrapped_type, null: true]
|
76
51
|
end
|
77
52
|
end
|
78
53
|
|
79
|
-
|
54
|
+
def unwrapped_model_input_type
|
55
|
+
type_class = graphql_model
|
56
|
+
return unless type_class
|
80
57
|
|
81
|
-
|
58
|
+
type_class.graphql.input(subtype).graphql_input_type
|
59
|
+
end
|
82
60
|
end
|
83
61
|
end
|
84
62
|
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphqlRails
|
4
|
+
module Attributes
|
5
|
+
# Contains shared parsing logic.
|
6
|
+
# Expects that including class has:
|
7
|
+
# * method "unparsed_type" which might be Instance of String, Symbol, GraphQL type or so
|
8
|
+
module TypeParseable
|
9
|
+
require_relative './type_name_info'
|
10
|
+
|
11
|
+
class UnknownTypeError < ArgumentError; end
|
12
|
+
|
13
|
+
TYPE_MAPPING = {
|
14
|
+
'id' => GraphQL::Types::ID,
|
15
|
+
|
16
|
+
'int' => GraphQL::Types::Int,
|
17
|
+
'integer' => GraphQL::Types::Int,
|
18
|
+
|
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
|
+
|
25
|
+
'bool' => GraphQL::Types::Boolean,
|
26
|
+
'boolean' => GraphQL::Types::Boolean,
|
27
|
+
|
28
|
+
'float' => GraphQL::Types::Float,
|
29
|
+
'double' => GraphQL::Types::Float,
|
30
|
+
'decimal' => GraphQL::Types::Float
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
WRAPPER_TYPES = [
|
34
|
+
GraphQL::Schema::List,
|
35
|
+
GraphQL::Schema::NonNull,
|
36
|
+
GraphQL::NonNullType,
|
37
|
+
GraphQL::ListType
|
38
|
+
].freeze
|
39
|
+
|
40
|
+
GRAPHQL_BASE_TYPES = [
|
41
|
+
GraphQL::BaseType,
|
42
|
+
GraphQL::ObjectType,
|
43
|
+
GraphQL::InputObjectType
|
44
|
+
].freeze
|
45
|
+
|
46
|
+
RAW_GRAPHQL_TYPES = (WRAPPER_TYPES + GRAPHQL_BASE_TYPES).freeze
|
47
|
+
|
48
|
+
def unwrapped_scalar_type
|
49
|
+
TYPE_MAPPING[nullable_inner_name.downcase.downcase]
|
50
|
+
end
|
51
|
+
|
52
|
+
def raw_graphql_type?
|
53
|
+
return true if RAW_GRAPHQL_TYPES.detect { |raw_type| unparsed_type.is_a?(raw_type) }
|
54
|
+
|
55
|
+
defined?(GraphQL::Schema::Member) &&
|
56
|
+
unparsed_type.is_a?(Class) &&
|
57
|
+
unparsed_type < GraphQL::Schema::Member
|
58
|
+
end
|
59
|
+
|
60
|
+
def core_scalar_type?
|
61
|
+
unwrapped_scalar_type.in?(TYPE_MAPPING.values)
|
62
|
+
end
|
63
|
+
|
64
|
+
def graphql_model
|
65
|
+
type_class = \
|
66
|
+
if unparsed_type.is_a?(Class) && unparsed_type < GraphqlRails::Model
|
67
|
+
unparsed_type
|
68
|
+
else
|
69
|
+
nullable_inner_name.safe_constantize
|
70
|
+
end
|
71
|
+
|
72
|
+
return if type_class.nil?
|
73
|
+
return unless type_class < GraphqlRails::Model
|
74
|
+
|
75
|
+
type_class
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
def unwrap_type(type)
|
81
|
+
unwrappable = type
|
82
|
+
unwrappable = unwrappable.of_type while wrapped_type?(unwrappable)
|
83
|
+
unwrappable
|
84
|
+
end
|
85
|
+
|
86
|
+
def wrapped_type?(type)
|
87
|
+
WRAPPER_TYPES.any? { |wrapper| type.is_a?(wrapper) }
|
88
|
+
end
|
89
|
+
|
90
|
+
def nullable_inner_name
|
91
|
+
type_name_info.nullable_inner_name
|
92
|
+
end
|
93
|
+
|
94
|
+
def list?
|
95
|
+
type_name_info.list?
|
96
|
+
end
|
97
|
+
|
98
|
+
def required_inner_type?
|
99
|
+
type_name_info.required_inner_type?
|
100
|
+
end
|
101
|
+
|
102
|
+
def required_list?
|
103
|
+
type_name_info.required_list?
|
104
|
+
end
|
105
|
+
|
106
|
+
def required?
|
107
|
+
type_name_info.required?
|
108
|
+
end
|
109
|
+
|
110
|
+
def type_name_info
|
111
|
+
@type_name_info ||= begin
|
112
|
+
type_name = \
|
113
|
+
if unparsed_type.respond_to?(:to_type_signature)
|
114
|
+
unparsed_type.to_type_signature
|
115
|
+
else
|
116
|
+
unparsed_type.to_s
|
117
|
+
end
|
118
|
+
TypeNameInfo.new(type_name)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def raise_not_supported_type_error
|
123
|
+
error_message = \
|
124
|
+
"Type #{unparsed_type.inspect} is not supported. " \
|
125
|
+
"Supported scalar types are: #{TypeParseable::TYPE_MAPPING.keys}. " \
|
126
|
+
'All the classes that includes `GraphqlRails::Model` are also supported as types.'
|
127
|
+
|
128
|
+
raise UnknownTypeError, error_message
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -1,44 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'graphql'
|
4
|
+
require 'graphql_rails/model/build_connection_type'
|
5
|
+
require 'graphql_rails/errors/error'
|
4
6
|
|
5
7
|
module GraphqlRails
|
6
8
|
module Attributes
|
7
9
|
# converts string value in to GraphQL type
|
8
10
|
class TypeParser
|
9
11
|
require_relative './type_name_info'
|
12
|
+
require_relative './type_parseable'
|
10
13
|
|
11
|
-
class
|
14
|
+
class NotSupportedFeature < GraphqlRails::Error; end
|
12
15
|
|
13
|
-
|
14
|
-
'id' => GraphQL::ID_TYPE,
|
16
|
+
include TypeParseable
|
15
17
|
|
16
|
-
|
17
|
-
'integer' => GraphQL::INT_TYPE,
|
18
|
+
delegate :list?, :required_inner_type?, :required_list?, :required?, to: :type_name_info
|
18
19
|
|
19
|
-
|
20
|
-
'str' => GraphQL::STRING_TYPE,
|
21
|
-
'text' => GraphQL::STRING_TYPE,
|
22
|
-
'time' => GraphQL::STRING_TYPE,
|
23
|
-
'date' => GraphQL::STRING_TYPE,
|
24
|
-
|
25
|
-
'bool' => GraphQL::BOOLEAN_TYPE,
|
26
|
-
'boolean' => GraphQL::BOOLEAN_TYPE,
|
27
|
-
|
28
|
-
'float' => GraphQL::FLOAT_TYPE,
|
29
|
-
'double' => GraphQL::FLOAT_TYPE,
|
30
|
-
'decimal' => GraphQL::FLOAT_TYPE
|
31
|
-
}.freeze
|
32
|
-
|
33
|
-
RAW_GRAPHQL_TYPES = [
|
34
|
-
GraphQL::Schema::List,
|
35
|
-
GraphQL::BaseType,
|
36
|
-
GraphQL::ObjectType,
|
37
|
-
GraphQL::InputObjectType
|
38
|
-
].freeze
|
39
|
-
|
40
|
-
def initialize(unparsed_type)
|
20
|
+
def initialize(unparsed_type, paginated: false)
|
41
21
|
@unparsed_type = unparsed_type
|
22
|
+
@paginated = paginated
|
23
|
+
end
|
24
|
+
|
25
|
+
def paginated?
|
26
|
+
@paginated
|
42
27
|
end
|
43
28
|
|
44
29
|
def graphql_type
|
@@ -51,25 +36,43 @@ module GraphqlRails
|
|
51
36
|
end
|
52
37
|
end
|
53
38
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
39
|
+
def type_arg
|
40
|
+
if paginated?
|
41
|
+
paginated_type_arg
|
42
|
+
elsif list?
|
43
|
+
list_type_arg
|
44
|
+
else
|
45
|
+
raw_unwrapped_type
|
46
|
+
end
|
59
47
|
end
|
60
48
|
|
61
49
|
protected
|
62
50
|
|
63
|
-
def
|
64
|
-
|
65
|
-
return unless type_class
|
51
|
+
def paginated_type_arg
|
52
|
+
return graphql_model.graphql.connection_type if graphql_model
|
66
53
|
|
67
|
-
|
54
|
+
raise NotSupportedFeature, 'pagination is only supported for models which include GraphqlRails::Model'
|
68
55
|
end
|
69
56
|
|
70
|
-
|
57
|
+
def list_type_arg
|
58
|
+
if required_inner_type?
|
59
|
+
[raw_unwrapped_type]
|
60
|
+
else
|
61
|
+
[raw_unwrapped_type, null: true]
|
62
|
+
end
|
63
|
+
end
|
71
64
|
|
72
|
-
|
65
|
+
def parsed_type
|
66
|
+
return unparsed_type if raw_graphql_type?
|
67
|
+
|
68
|
+
type_by_name
|
69
|
+
end
|
70
|
+
|
71
|
+
def raw_unwrapped_type
|
72
|
+
@raw_unwrapped_type ||= unwrap_type(parsed_type)
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
73
76
|
|
74
77
|
attr_reader :unparsed_type
|
75
78
|
|
@@ -91,26 +94,27 @@ module GraphqlRails
|
|
91
94
|
end
|
92
95
|
end
|
93
96
|
|
94
|
-
def raw_graphql_type?
|
95
|
-
return true if RAW_GRAPHQL_TYPES.detect { |raw_type| unparsed_type.is_a?(raw_type) }
|
96
|
-
|
97
|
-
defined?(GraphQL::Schema::Member) &&
|
98
|
-
unparsed_type.is_a?(Class) &&
|
99
|
-
unparsed_type < GraphQL::Schema::Member
|
100
|
-
end
|
101
|
-
|
102
97
|
def type_name_info
|
103
|
-
@type_name_info ||=
|
98
|
+
@type_name_info ||= begin
|
99
|
+
type_name = \
|
100
|
+
if unparsed_type.respond_to?(:to_type_signature)
|
101
|
+
unparsed_type.to_type_signature
|
102
|
+
else
|
103
|
+
unparsed_type.to_s
|
104
|
+
end
|
105
|
+
TypeNameInfo.new(type_name)
|
106
|
+
end
|
104
107
|
end
|
105
108
|
|
106
109
|
def type_by_name
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
110
|
+
unwrapped_scalar_type || unwrapped_model_type || raise_not_supported_type_error
|
111
|
+
end
|
112
|
+
|
113
|
+
def unwrapped_model_type
|
114
|
+
type_class = graphql_model
|
115
|
+
return unless type_class
|
116
|
+
|
117
|
+
type_class.graphql.graphql_type
|
114
118
|
end
|
115
119
|
end
|
116
120
|
end
|