graphql_rails 0.1.0 → 0.2.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/.gitignore +1 -0
- data/Gemfile.lock +2 -2
- data/README.md +76 -8
- data/graphql_rails.gemspec +1 -1
- data/lib/graphql_rails/attribute.rb +7 -42
- data/lib/graphql_rails/attribute/attribute_type_parser.rb +99 -0
- data/lib/graphql_rails/controller.rb +17 -5
- data/lib/graphql_rails/controller/action.rb +93 -0
- data/lib/graphql_rails/controller/action_configuration.rb +1 -2
- data/lib/graphql_rails/controller/controller_function.rb +7 -6
- data/lib/graphql_rails/controller/request.rb +3 -3
- data/lib/graphql_rails/model.rb +1 -1
- data/lib/graphql_rails/model/configuration.rb +14 -50
- data/lib/graphql_rails/model/graphql_type_builder.rb +37 -0
- data/lib/graphql_rails/router.rb +36 -19
- data/lib/graphql_rails/router/{mutation_action.rb → mutation_route.rb} +2 -2
- data/lib/graphql_rails/router/{query_action.rb → query_route.rb} +2 -2
- data/lib/graphql_rails/router/resource_routes_builder.rb +82 -0
- data/lib/graphql_rails/router/route.rb +40 -0
- data/lib/graphql_rails/router/schema_builder.rb +9 -5
- data/lib/graphql_rails/rspec_controller_helpers.rb +94 -0
- data/lib/graphql_rails/version.rb +1 -1
- metadata +14 -29
- data/lib/graphiti.rb +0 -10
- data/lib/graphiti/attribute.rb +0 -86
- data/lib/graphiti/controller.rb +0 -54
- data/lib/graphiti/controller/action_configuration.rb +0 -46
- data/lib/graphiti/controller/configuration.rb +0 -32
- data/lib/graphiti/controller/controller_function.rb +0 -41
- data/lib/graphiti/controller/request.rb +0 -40
- data/lib/graphiti/errors/execution_error.rb +0 -18
- data/lib/graphiti/errors/validation_error.rb +0 -26
- data/lib/graphiti/model.rb +0 -33
- data/lib/graphiti/model/configuration.rb +0 -81
- data/lib/graphiti/router.rb +0 -65
- data/lib/graphiti/router/action.rb +0 -21
- data/lib/graphiti/router/mutation_action.rb +0 -18
- data/lib/graphiti/router/query_action.rb +0 -18
- data/lib/graphiti/router/resource_actions_builder.rb +0 -82
- data/lib/graphiti/router/schema_builder.rb +0 -37
- data/lib/graphiti/version.rb +0 -5
- data/lib/graphql_rails/controller/action_path_parser.rb +0 -75
- data/lib/graphql_rails/router/action.rb +0 -21
- data/lib/graphql_rails/router/resource_actions_builder.rb +0 -82
@@ -38,8 +38,7 @@ module GraphqlRails
|
|
38
38
|
|
39
39
|
def permit_attribute(name, type = nil)
|
40
40
|
field_name = name.to_s.remove(/!\Z/)
|
41
|
-
|
42
|
-
attributes[field_name] = Attribute.new(field_name, type, required: required)
|
41
|
+
attributes[field_name] = Attribute.new(field_name, type)
|
43
42
|
end
|
44
43
|
end
|
45
44
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'graphql_rails/controller/
|
3
|
+
require 'graphql_rails/controller/action'
|
4
4
|
require_relative 'request'
|
5
|
+
require_relative 'action'
|
5
6
|
|
6
7
|
module GraphqlRails
|
7
8
|
class Controller
|
@@ -16,16 +17,16 @@ module GraphqlRails
|
|
16
17
|
@type = return_type
|
17
18
|
end
|
18
19
|
|
19
|
-
def self.
|
20
|
-
|
20
|
+
def self.from_route(route)
|
21
|
+
action = Action.new(route)
|
21
22
|
|
22
23
|
action_function = Class.new(self) do
|
23
|
-
|
24
|
-
argument(
|
24
|
+
action.arguments.each do |attribute|
|
25
|
+
argument(attribute.field_name, attribute.graphql_field_type)
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
|
-
action_function.new(
|
29
|
+
action_function.new(action.controller, action.name, action.return_type)
|
29
30
|
end
|
30
31
|
|
31
32
|
def call(object, inputs, ctx)
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'graphql_rails/errors/execution_error'
|
4
4
|
|
5
5
|
module GraphqlRails
|
6
6
|
class Controller
|
7
7
|
# Contains all info related with single request to controller
|
8
8
|
class Request
|
9
9
|
attr_accessor :object_to_return
|
10
|
-
attr_reader :errors
|
10
|
+
attr_reader :errors, :context
|
11
11
|
|
12
12
|
def initialize(graphql_object, inputs, context)
|
13
13
|
@graphql_object = graphql_object
|
@@ -34,7 +34,7 @@ module GraphqlRails
|
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
|
-
attr_reader :graphql_object, :inputs
|
37
|
+
attr_reader :graphql_object, :inputs
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
data/lib/graphql_rails/model.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'graphql_rails/attribute'
|
4
|
+
require 'graphql_rails/model/graphql_type_builder'
|
4
5
|
|
5
6
|
module GraphqlRails
|
6
7
|
module Model
|
@@ -13,68 +14,31 @@ module GraphqlRails
|
|
13
14
|
@attributes = {}
|
14
15
|
end
|
15
16
|
|
16
|
-
def
|
17
|
-
|
17
|
+
def name(type_name = nil)
|
18
|
+
@name ||= type_name
|
18
19
|
end
|
19
20
|
|
20
|
-
def
|
21
|
-
|
21
|
+
def description(description = nil)
|
22
|
+
@description ||= description
|
23
|
+
end
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
elsif defined?(ActiveRecord) && model_class < ActiveRecord::Base
|
26
|
-
assign_default_active_record_attributes(except: except)
|
27
|
-
end
|
25
|
+
def attribute(attribute_name, type: nil, hidden: false, property: attribute_name)
|
26
|
+
attributes[attribute_name.to_s] = Attribute.new(attribute_name, type, hidden: hidden, property: property)
|
28
27
|
end
|
29
28
|
|
30
29
|
def graphql_type
|
31
|
-
@graphql_type ||=
|
30
|
+
@graphql_type ||= begin
|
31
|
+
type_name = name || name_by_class_name
|
32
|
+
GrapqhlTypeBuilder.new(name: type_name, description: description, attributes: attributes).call
|
33
|
+
end
|
32
34
|
end
|
33
35
|
|
34
36
|
private
|
35
37
|
|
36
38
|
attr_reader :model_class
|
37
39
|
|
38
|
-
def
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
def graphql_type_name
|
43
|
-
model_class.name.split('::').last
|
44
|
-
end
|
45
|
-
|
46
|
-
def generate_graphql_type(type_name, attributes)
|
47
|
-
GraphQL::ObjectType.define do
|
48
|
-
name(type_name)
|
49
|
-
description("Generated programmatically from model: #{type_name}")
|
50
|
-
|
51
|
-
attributes.each_value do |attribute|
|
52
|
-
field(attribute.field_name, attribute.graphql_field_type, property: attribute.name.to_sym)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def assign_default_mongoid_attributes(except: [])
|
58
|
-
allowed_fields = model_class.fields.except('_type', '_id', *except)
|
59
|
-
|
60
|
-
attribute('id', type: 'id')
|
61
|
-
|
62
|
-
allowed_fields.each_value do |field|
|
63
|
-
attribute(field.name, type: field.type.to_s.split('::').last)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def assign_default_active_record_attributes(except: [])
|
68
|
-
allowed_fields = model_class.columns.index_by(&:name).except('type', *except)
|
69
|
-
|
70
|
-
allowed_fields.each_value do |field|
|
71
|
-
field_type = field.cast_type.class.to_s.downcase.split('::').last
|
72
|
-
field_type = 'string' if field_type.ends_with?('string')
|
73
|
-
field_type = 'date' if field_type.include?('date')
|
74
|
-
field_type = 'time' if field_type.include?('time')
|
75
|
-
|
76
|
-
attribute(field.name, type: field_type.to_s.split('::').last)
|
77
|
-
end
|
40
|
+
def name_by_class_name
|
41
|
+
@name_by_class_name ||= model_class.name.split('::').last
|
78
42
|
end
|
79
43
|
end
|
80
44
|
end
|
@@ -0,0 +1,37 @@
|
|
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 GrapqhlTypeBuilder
|
7
|
+
def initialize(name:, description: nil, attributes:)
|
8
|
+
@name = name
|
9
|
+
@attributes = attributes
|
10
|
+
@description = description
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
type_name = name
|
15
|
+
type_description = description
|
16
|
+
type_attributes = visible_attributes
|
17
|
+
|
18
|
+
GraphQL::ObjectType.define do
|
19
|
+
name(type_name)
|
20
|
+
description(type_description)
|
21
|
+
|
22
|
+
type_attributes.each_value do |attribute|
|
23
|
+
field(attribute.field_name, attribute.graphql_field_type, property: attribute.property.to_sym)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :model_configuration, :attributes, :name, :description
|
31
|
+
|
32
|
+
def visible_attributes
|
33
|
+
attributes.reject { |_name, attribute| attribute.hidden? }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/graphql_rails/router.rb
CHANGED
@@ -2,64 +2,81 @@
|
|
2
2
|
|
3
3
|
require 'active_support/core_ext/string/inflections'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
require 'graphql_rails/router/schema_builder'
|
6
|
+
require 'graphql_rails/router/mutation_route'
|
7
|
+
require 'graphql_rails/router/query_route'
|
8
|
+
require 'graphql_rails/router/resource_routes_builder'
|
9
9
|
|
10
10
|
module GraphqlRails
|
11
11
|
# graphql router that mimics Rails.application.routes
|
12
12
|
class Router
|
13
|
+
RAW_ACTION_NAMES = %i[rescue_from query_analyzer instrument].freeze
|
14
|
+
|
13
15
|
def self.draw(&block)
|
14
16
|
router = new
|
15
17
|
router.instance_eval(&block)
|
16
18
|
router.graphql_schema
|
17
19
|
end
|
18
20
|
|
19
|
-
attr_reader :
|
21
|
+
attr_reader :routes, :namespace_name, :raw_graphql_actions
|
20
22
|
|
21
23
|
def initialize(module_name: '')
|
22
24
|
@module_name = module_name
|
23
|
-
@
|
25
|
+
@routes ||= Set.new
|
26
|
+
@raw_graphql_actions ||= []
|
24
27
|
end
|
25
28
|
|
26
29
|
def scope(**options, &block)
|
27
30
|
full_module_name = [module_name, options[:module]].reject(&:empty?).join('/')
|
28
31
|
scoped_router = self.class.new(module_name: full_module_name)
|
29
32
|
scoped_router.instance_eval(&block)
|
30
|
-
|
33
|
+
routes.merge(scoped_router.routes)
|
31
34
|
end
|
32
35
|
|
33
36
|
def resources(name, **options, &block)
|
34
|
-
builder_options =
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
builder_options = default_route_options.merge(options)
|
38
|
+
routes_builder = ResourceRoutesBuilder.new(name, **builder_options)
|
39
|
+
routes_builder.instance_eval(&block) if block
|
40
|
+
routes.merge(routes_builder.routes)
|
38
41
|
end
|
39
42
|
|
40
43
|
def query(name, **options)
|
41
|
-
|
44
|
+
routes << build_route(QueryRoute, name, **options)
|
42
45
|
end
|
43
46
|
|
44
47
|
def mutation(name, **options)
|
45
|
-
|
48
|
+
routes << build_route(MutationRoute, name, **options)
|
49
|
+
end
|
50
|
+
|
51
|
+
RAW_ACTION_NAMES.each do |action_name|
|
52
|
+
define_method(action_name) do |*args, &block|
|
53
|
+
add_raw_action(action_name, *args, &block)
|
54
|
+
end
|
46
55
|
end
|
47
56
|
|
48
57
|
def graphql_schema
|
49
|
-
SchemaBuilder.new(
|
58
|
+
SchemaBuilder.new(
|
59
|
+
queries: routes.select(&:query?),
|
60
|
+
mutations: routes.select(&:mutation?),
|
61
|
+
raw_actions: raw_graphql_actions
|
62
|
+
).call
|
50
63
|
end
|
51
64
|
|
52
65
|
private
|
53
66
|
|
54
67
|
attr_reader :module_name
|
55
68
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
69
|
+
def add_raw_action(name, *args, &block)
|
70
|
+
raw_graphql_actions << { name: name, args: args, block: block }
|
71
|
+
end
|
72
|
+
|
73
|
+
def build_route(route_builder, name, **options)
|
74
|
+
route_options = default_route_options.merge(options)
|
75
|
+
route_builder.new(name, route_options)
|
59
76
|
end
|
60
77
|
|
61
|
-
def
|
62
|
-
{ module: module_name }
|
78
|
+
def default_route_options
|
79
|
+
{ module: module_name, on: :member }
|
63
80
|
end
|
64
81
|
end
|
65
82
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'route'
|
4
4
|
|
5
5
|
module GraphqlRails
|
6
6
|
class Router
|
7
7
|
# stores mutation type graphql action info
|
8
|
-
class
|
8
|
+
class MutationRoute < Route
|
9
9
|
def query?
|
10
10
|
false
|
11
11
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'query_route'
|
4
|
+
require_relative 'mutation_route'
|
5
|
+
|
6
|
+
module GraphqlRails
|
7
|
+
class Router
|
8
|
+
# Generates graphql routes based on resource name and options
|
9
|
+
class ResourceRoutesBuilder
|
10
|
+
AVAILABLE_ROUTES = %i[show index create update destroy].freeze
|
11
|
+
|
12
|
+
def initialize(name, only: nil, except: [], **options)
|
13
|
+
@name = name.to_s
|
14
|
+
|
15
|
+
@options = options
|
16
|
+
@autogenerated_action_names = initial_action_names(only, except, AVAILABLE_ROUTES)
|
17
|
+
end
|
18
|
+
|
19
|
+
def routes
|
20
|
+
@routes ||= initial_routes
|
21
|
+
end
|
22
|
+
|
23
|
+
def query(*args)
|
24
|
+
routes << build_query(*args)
|
25
|
+
end
|
26
|
+
|
27
|
+
def mutation(*args)
|
28
|
+
routes << build_mutation(*args)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :autogenerated_action_names, :name, :options
|
34
|
+
|
35
|
+
def initial_routes
|
36
|
+
routes = initial_query_routes
|
37
|
+
routes << build_mutation(:create, on: :member) if autogenerated_action_names.include?(:create)
|
38
|
+
routes << build_mutation(:update, on: :member) if autogenerated_action_names.include?(:update)
|
39
|
+
routes << build_mutation(:destroy, on: :member) if autogenerated_action_names.include?(:destroy)
|
40
|
+
routes
|
41
|
+
end
|
42
|
+
|
43
|
+
def initial_query_routes
|
44
|
+
routes = Set.new
|
45
|
+
|
46
|
+
if autogenerated_action_names.include?(:show)
|
47
|
+
routes << build_route(QueryRoute, 'show', to: "#{name}#show", prefix: '', on: :member)
|
48
|
+
end
|
49
|
+
|
50
|
+
if autogenerated_action_names.include?(:index)
|
51
|
+
routes << build_route(QueryRoute, 'index', to: "#{name}#index", prefix: '', on: :collection)
|
52
|
+
end
|
53
|
+
|
54
|
+
routes
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_mutation(*args)
|
58
|
+
build_route(MutationRoute, *args)
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_query(*args)
|
62
|
+
build_route(QueryRoute, *args)
|
63
|
+
end
|
64
|
+
|
65
|
+
def build_route(builder, action, prefix: action, on: :member, **custom_options)
|
66
|
+
action_options = options.merge(custom_options)
|
67
|
+
action_name = [prefix, resource_name(on)].reject(&:empty?).join('_')
|
68
|
+
builder.new(action_name, to: "#{name}##{action}", **action_options)
|
69
|
+
end
|
70
|
+
|
71
|
+
def initial_action_names(only, except, available)
|
72
|
+
alowed_routes = Array(only || available) & available
|
73
|
+
only_routes = alowed_routes.map(&:to_sym) - Array(except).map(&:to_sym)
|
74
|
+
Set.new(only_routes)
|
75
|
+
end
|
76
|
+
|
77
|
+
def resource_name(type)
|
78
|
+
type.to_sym == :member ? name.singularize : name
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../controller/controller_function'
|
4
|
+
|
5
|
+
module GraphqlRails
|
6
|
+
class Router
|
7
|
+
# Generic class for any type graphql action. Should not be used directly
|
8
|
+
class Route
|
9
|
+
attr_reader :name, :module_name, :on
|
10
|
+
|
11
|
+
def initialize(name, to:, on:, **options)
|
12
|
+
@name = name.to_s.camelize(:lower)
|
13
|
+
@module_name = options[:module].to_s
|
14
|
+
@relative_path = to
|
15
|
+
@on = on.to_sym
|
16
|
+
end
|
17
|
+
|
18
|
+
def path
|
19
|
+
return relative_path if module_name.empty?
|
20
|
+
[module_name, relative_path].join('/')
|
21
|
+
end
|
22
|
+
|
23
|
+
def collection?
|
24
|
+
on == :collection
|
25
|
+
end
|
26
|
+
|
27
|
+
def member?
|
28
|
+
on == :member
|
29
|
+
end
|
30
|
+
|
31
|
+
def options
|
32
|
+
{ function: Controller::ControllerFunction.build(path) }
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
attr_reader :relative_path
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|