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
@@ -36,7 +36,11 @@ module GraphqlRails
36
36
  end
37
37
 
38
38
  def type_args
39
- [type_parser.type_arg, null: !type_parser.required?]
39
+ [type_parser.type_arg]
40
+ end
41
+
42
+ def type_options
43
+ { null: !type_parser.required? }
40
44
  end
41
45
 
42
46
  private
@@ -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
@@ -51,8 +51,7 @@ module GraphqlRails
51
51
  params
52
52
  else
53
53
  filter_options = Rails.configuration.filter_parameters
54
- parametter_filter = ActionDispatch::Http::ParameterFilter.new(filter_options)
55
- parametter_filter.filter(params)
54
+ parameter_filter_class.new(filter_options).filter(params)
56
55
  end
57
56
  end
58
57
 
@@ -61,6 +60,12 @@ module GraphqlRails
61
60
 
62
61
  Rails.application.config.filter_parameters || []
63
62
  end
63
+
64
+ def parameter_filter_class
65
+ return ActiveSupport::ParameterFilter if Object.const_defined?('ActiveSupport::ParameterFilter')
66
+
67
+ ActionDispatch::Http::ParameterFilter
68
+ end
64
69
  end
65
70
  end
66
71
  end
@@ -16,7 +16,7 @@ module GraphqlRails
16
16
  end
17
17
 
18
18
  def errors=(new_errors)
19
- @errors = FormatErrors.call(new_errors)
19
+ @errors = FormatErrors.call(not_formatted_errors: new_errors)
20
20
 
21
21
  @errors.each { |error| context.add_error(error) }
22
22
  end
@@ -12,7 +12,7 @@ module GraphqlRails
12
12
  class FormatErrors
13
13
  include Service
14
14
 
15
- def initialize(not_formatted_errors)
15
+ def initialize(not_formatted_errors:)
16
16
  @not_formatted_errors = not_formatted_errors
17
17
  end
18
18
 
@@ -71,9 +71,5 @@ module GraphqlRails
71
71
  self.class.new(decorator: decorator, relation: new_relation, decorator_args: decorator_args)
72
72
  end
73
73
  end
74
-
75
- GraphQL::Relay::BaseConnection.register_connection_implementation(
76
- RelationDecorator, GraphQL::Relay::RelationConnection
77
- )
78
74
  end
79
75
  end
@@ -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
@@ -30,7 +30,11 @@ module GraphqlRails
30
30
  graphql_name("#{type.graphql_name}Connection")
31
31
  edge_type(edge_type)
32
32
 
33
- field :total, Integer, null: false, resolve: CountItems
33
+ field :total, Integer, null: false
34
+
35
+ def total
36
+ CountItems.call(object)
37
+ end
34
38
  end
35
39
  end
36
40
 
@@ -10,7 +10,7 @@ module GraphqlRails
10
10
 
11
11
  include ::GraphqlRails::Service
12
12
 
13
- def initialize(graphql_object, _args, _ctx)
13
+ def initialize(graphql_object)
14
14
  @graphql_object = graphql_object
15
15
  end
16
16
 
@@ -27,7 +27,7 @@ module GraphqlRails
27
27
  attr_reader :graphql_object
28
28
 
29
29
  def list
30
- graphql_object.nodes
30
+ graphql_object.items
31
31
  end
32
32
 
33
33
  def active_record?
@@ -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
- model.send(method_name, **custom_keyword_arguments)
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(type_name = nil)
13
- @name = type_name if type_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/build_graphql_type'
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
- attribute.public_send(method_name, args)
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 ||= BuildGraphqlType.call(
58
- name: name, description: description, attributes: attributes
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
 
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphqlRails
4
+ module Model
5
+ # stores information about model specific config, like attributes and types
6
+ class FindOrBuildGraphqlType
7
+ require 'graphql_rails/concerns/service'
8
+ require 'graphql_rails/model/find_or_build_graphql_type_class'
9
+ require 'graphql_rails/model/add_fields_to_graphql_type'
10
+
11
+ include ::GraphqlRails::Service
12
+
13
+ def initialize(name:, description:, attributes:, type_name:)
14
+ @name = name
15
+ @description = description
16
+ @attributes = attributes
17
+ @type_name = type_name
18
+ end
19
+
20
+ def call
21
+ klass.tap { add_fields_to_graphql_type if new_class? }
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :name, :description, :attributes, :type_name
27
+
28
+ delegate :klass, :new_class?, to: :type_class_finder
29
+
30
+ def type_class_finder
31
+ @type_class_finder ||= FindOrBuildGraphqlTypeClass.new(
32
+ name: name,
33
+ type_name: type_name,
34
+ description: description
35
+ )
36
+ end
37
+
38
+ def add_fields_to_graphql_type
39
+ AddFieldsToGraphqlType.call(klass: klass, attributes: attributes.values.select(&:scalar_type?))
40
+
41
+ attributes.values.reject(&:scalar_type?).tap do |dynamic_attributes|
42
+ find_or_build_dynamic_graphql_types(dynamic_attributes) do |name, description, attributes, type_name|
43
+ self.class.call(
44
+ name: name, description: description,
45
+ attributes: attributes, type_name: type_name
46
+ )
47
+ end
48
+ AddFieldsToGraphqlType.call(klass: klass, attributes: dynamic_attributes)
49
+ end
50
+ end
51
+
52
+ def find_or_build_dynamic_graphql_types(dynamic_attributes)
53
+ dynamic_attributes.each do |attribute|
54
+ yield(
55
+ attribute.graphql_model.graphql.name,
56
+ attribute.graphql_model.graphql.description,
57
+ attribute.graphql_model.graphql.attributes,
58
+ attribute.graphql_model.graphql.type_name
59
+ )
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphqlRails
4
+ module Model
5
+ # Initializes class to define graphql type and fields.
6
+ class FindOrBuildGraphqlTypeClass
7
+ require 'graphql_rails/concerns/service'
8
+
9
+ include ::GraphqlRails::Service
10
+
11
+ def initialize(name:, type_name:, description: nil)
12
+ @name = name
13
+ @type_name = type_name
14
+ @description = description
15
+ @new_class = false
16
+ end
17
+
18
+ def klass
19
+ @klass ||= Object.const_defined?(type_name) && Object.const_get(type_name) || build_graphql_type_klass
20
+ end
21
+
22
+ def new_class?
23
+ new_class
24
+ end
25
+
26
+ private
27
+
28
+ attr_accessor :new_class
29
+ attr_reader :name, :type_name, :description
30
+
31
+ def build_graphql_type_klass
32
+ graphql_type_name = name
33
+ graphql_type_description = description
34
+
35
+ graphql_type_klass = Class.new(GraphQL::Schema::Object) do
36
+ graphql_name(graphql_type_name)
37
+ description(graphql_type_description)
38
+ end
39
+
40
+ self.new_class = true
41
+
42
+ Object.const_set(type_name, graphql_type_klass)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -85,7 +85,7 @@ module GraphqlRails
85
85
  default_options = { module_name: module_name, group_names: group_names }
86
86
  full_options = default_options.merge(new_router_options)
87
87
 
88
- self.class.new(full_options)
88
+ self.class.new(**full_options)
89
89
  end
90
90
 
91
91
  def add_raw_action(name, *args, &block)
@@ -93,7 +93,7 @@ module GraphqlRails
93
93
  end
94
94
 
95
95
  def build_route(route_builder, name, **options)
96
- route_builder.new(name, full_route_options(options))
96
+ route_builder.new(name, **full_route_options(options))
97
97
  end
98
98
 
99
99
  def full_route_options(extra_options)
@@ -20,12 +20,12 @@ module GraphqlRails
20
20
  @routes ||= initial_routes
21
21
  end
22
22
 
23
- def query(*args)
24
- routes << build_query(*args)
23
+ def query(*args, **kwargs)
24
+ routes << build_query(*args, **kwargs)
25
25
  end
26
26
 
27
- def mutation(*args)
28
- routes << build_mutation(*args)
27
+ def mutation(*args, **kwargs)
28
+ routes << build_mutation(*args, **kwargs)
29
29
  end
30
30
 
31
31
  private
@@ -54,12 +54,12 @@ module GraphqlRails
54
54
  routes
55
55
  end
56
56
 
57
- def build_mutation(*args)
58
- build_route(MutationRoute, *args)
57
+ def build_mutation(*args, **kwargs)
58
+ build_route(MutationRoute, *args, **kwargs)
59
59
  end
60
60
 
61
- def build_query(*args)
62
- build_route(QueryRoute, *args)
61
+ def build_query(*args, **kwargs)
62
+ build_route(QueryRoute, *args, **kwargs)
63
63
  end
64
64
 
65
65
  # rubocop:disable Metrics/ParameterLists
@@ -33,16 +33,12 @@ module GraphqlRails
33
33
  groups.include?(group_name&.to_sym)
34
34
  end
35
35
 
36
- def field_args
37
- options = {}
38
-
36
+ def field_options
39
37
  if function
40
- options[:function] = function
38
+ { function: function }
41
39
  else
42
- options[:resolver] = resolver
40
+ { resolver: resolver }
43
41
  end
44
-
45
- [name, options]
46
42
  end
47
43
 
48
44
  private
@@ -21,6 +21,10 @@ module GraphqlRails
21
21
  raw = raw_actions
22
22
 
23
23
  Class.new(GraphQL::Schema) do
24
+ connections.add(
25
+ GraphqlRails::Decorator::RelationDecorator,
26
+ GraphQL::Pagination::ActiveRecordRelationConnection
27
+ )
24
28
  cursor_encoder(Router::PlainCursorEncoder)
25
29
  raw.each { |action| send(action[:name], *action[:args], &action[:block]) }
26
30
 
@@ -46,7 +50,7 @@ module GraphqlRails
46
50
  graphql_name(type_name)
47
51
 
48
52
  group_routes.each do |route|
49
- field(*route.field_args)
53
+ field(*route.name, **route.field_options)
50
54
  end
51
55
 
52
56
  def self.inspect