cuprum-rails 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +145 -0
- data/DEVELOPMENT.md +20 -0
- data/README.md +356 -63
- data/lib/cuprum/rails/action.rb +32 -16
- data/lib/cuprum/rails/actions/create.rb +62 -15
- data/lib/cuprum/rails/actions/destroy.rb +23 -7
- data/lib/cuprum/rails/actions/edit.rb +23 -7
- data/lib/cuprum/rails/actions/index.rb +30 -10
- data/lib/cuprum/rails/actions/middleware/associations/cache.rb +112 -0
- data/lib/cuprum/rails/actions/middleware/associations/find.rb +23 -0
- data/lib/cuprum/rails/actions/middleware/associations/parent.rb +70 -0
- data/lib/cuprum/rails/actions/middleware/associations/query.rb +140 -0
- data/lib/cuprum/rails/actions/middleware/associations.rb +12 -0
- data/lib/cuprum/rails/actions/middleware/log_request.rb +126 -0
- data/lib/cuprum/rails/actions/middleware/log_result.rb +51 -0
- data/lib/cuprum/rails/actions/middleware/resources/find.rb +44 -0
- data/lib/cuprum/rails/actions/middleware/resources/query.rb +91 -0
- data/lib/cuprum/rails/actions/middleware/resources.rb +11 -0
- data/lib/cuprum/rails/actions/middleware.rb +13 -0
- data/lib/cuprum/rails/actions/new.rb +16 -4
- data/lib/cuprum/rails/actions/parameter_validation.rb +60 -0
- data/lib/cuprum/rails/actions/resource_action.rb +119 -42
- data/lib/cuprum/rails/actions/show.rb +23 -7
- data/lib/cuprum/rails/actions/update.rb +70 -22
- data/lib/cuprum/rails/actions.rb +11 -7
- data/lib/cuprum/rails/collection.rb +27 -47
- data/lib/cuprum/rails/command.rb +3 -1
- data/lib/cuprum/rails/commands/destroy_one.rb +10 -6
- data/lib/cuprum/rails/commands/find_many.rb +8 -1
- data/lib/cuprum/rails/commands/find_matching.rb +1 -1
- data/lib/cuprum/rails/commands/find_one.rb +8 -0
- data/lib/cuprum/rails/commands/insert_one.rb +17 -6
- data/lib/cuprum/rails/commands/update_one.rb +16 -5
- data/lib/cuprum/rails/constraints/parameters_contract.rb +14 -0
- data/lib/cuprum/rails/constraints.rb +10 -0
- data/lib/cuprum/rails/controller.rb +12 -2
- data/lib/cuprum/rails/controllers/action.rb +100 -0
- data/lib/cuprum/rails/controllers/class_methods/actions.rb +33 -7
- data/lib/cuprum/rails/controllers/class_methods/configuration.rb +36 -0
- data/lib/cuprum/rails/controllers/class_methods/middleware.rb +88 -0
- data/lib/cuprum/rails/controllers/class_methods/validations.rb +2 -2
- data/lib/cuprum/rails/controllers/configuration.rb +41 -1
- data/lib/cuprum/rails/controllers/middleware.rb +59 -0
- data/lib/cuprum/rails/controllers.rb +2 -0
- data/lib/cuprum/rails/errors/invalid_parameters.rb +55 -0
- data/lib/cuprum/rails/errors/invalid_statement.rb +11 -0
- data/lib/cuprum/rails/errors/missing_parameter.rb +42 -0
- data/lib/cuprum/rails/errors/resource_error.rb +46 -0
- data/lib/cuprum/rails/errors.rb +6 -1
- data/lib/cuprum/rails/map_errors.rb +29 -1
- data/lib/cuprum/rails/query.rb +1 -1
- data/lib/cuprum/rails/repository.rb +12 -25
- data/lib/cuprum/rails/request.rb +149 -60
- data/lib/cuprum/rails/resource.rb +119 -85
- data/lib/cuprum/rails/responders/base_responder.rb +78 -0
- data/lib/cuprum/rails/responders/html/plural_resource.rb +9 -39
- data/lib/cuprum/rails/responders/html/rendering.rb +81 -0
- data/lib/cuprum/rails/responders/html/resource.rb +107 -0
- data/lib/cuprum/rails/responders/html/singular_resource.rb +9 -38
- data/lib/cuprum/rails/responders/html.rb +2 -0
- data/lib/cuprum/rails/responders/html_responder.rb +8 -52
- data/lib/cuprum/rails/responders/json/resource.rb +3 -3
- data/lib/cuprum/rails/responders/json_responder.rb +31 -16
- data/lib/cuprum/rails/responders/matching.rb +29 -27
- data/lib/cuprum/rails/responders/serialization.rb +11 -9
- data/lib/cuprum/rails/responders.rb +1 -0
- data/lib/cuprum/rails/responses/head_response.rb +24 -0
- data/lib/cuprum/rails/responses/html/redirect_back_response.rb +55 -0
- data/lib/cuprum/rails/responses/html/redirect_response.rb +19 -4
- data/lib/cuprum/rails/responses/html/render_response.rb +17 -5
- data/lib/cuprum/rails/responses/html.rb +6 -2
- data/lib/cuprum/rails/responses.rb +1 -0
- data/lib/cuprum/rails/result.rb +36 -0
- data/lib/cuprum/rails/routes.rb +36 -23
- data/lib/cuprum/rails/rspec/contract_helpers.rb +57 -0
- data/lib/cuprum/rails/rspec/contracts/action_contracts.rb +754 -0
- data/lib/cuprum/rails/rspec/contracts/actions/create_contracts.rb +289 -0
- data/lib/cuprum/rails/rspec/contracts/actions/destroy_contracts.rb +164 -0
- data/lib/cuprum/rails/rspec/contracts/actions/edit_contracts.rb +73 -0
- data/lib/cuprum/rails/rspec/contracts/actions/index_contracts.rb +108 -0
- data/lib/cuprum/rails/rspec/contracts/actions/new_contracts.rb +111 -0
- data/lib/cuprum/rails/rspec/contracts/actions/show_contracts.rb +72 -0
- data/lib/cuprum/rails/rspec/contracts/actions/update_contracts.rb +263 -0
- data/lib/cuprum/rails/rspec/contracts/actions.rb +8 -0
- data/lib/cuprum/rails/rspec/contracts/command_contracts.rb +479 -0
- data/lib/cuprum/rails/rspec/contracts/responder_contracts.rb +232 -0
- data/lib/cuprum/rails/rspec/contracts/routes_contracts.rb +363 -0
- data/lib/cuprum/rails/rspec/contracts/serializers_contracts.rb +70 -0
- data/lib/cuprum/rails/rspec/contracts.rb +8 -0
- data/lib/cuprum/rails/rspec/matchers/be_a_result_matcher.rb +64 -0
- data/lib/cuprum/rails/rspec/matchers.rb +41 -0
- data/lib/cuprum/rails/serializers/base_serializer.rb +60 -0
- data/lib/cuprum/rails/serializers/context.rb +84 -0
- data/lib/cuprum/rails/serializers/json/active_record_serializer.rb +2 -2
- data/lib/cuprum/rails/serializers/json/array_serializer.rb +9 -8
- data/lib/cuprum/rails/serializers/json/attributes_serializer.rb +95 -172
- data/lib/cuprum/rails/serializers/json/error_serializer.rb +2 -2
- data/lib/cuprum/rails/serializers/json/hash_serializer.rb +9 -8
- data/lib/cuprum/rails/serializers/json/identity_serializer.rb +3 -3
- data/lib/cuprum/rails/serializers/json/properties_serializer.rb +252 -0
- data/lib/cuprum/rails/serializers/json.rb +2 -1
- data/lib/cuprum/rails/serializers.rb +3 -1
- data/lib/cuprum/rails/version.rb +1 -1
- data/lib/cuprum/rails.rb +19 -16
- metadata +73 -131
- data/lib/cuprum/rails/controller_action.rb +0 -121
- data/lib/cuprum/rails/errors/missing_parameters.rb +0 -33
- data/lib/cuprum/rails/errors/missing_primary_key.rb +0 -46
- data/lib/cuprum/rails/errors/undefined_permitted_attributes.rb +0 -34
- data/lib/cuprum/rails/rspec/command_contract.rb +0 -460
- data/lib/cuprum/rails/rspec/define_route_contract.rb +0 -84
- data/lib/cuprum/rails/serializers/json/serializer.rb +0 -66
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'cuprum/rails/
|
3
|
+
require 'cuprum/rails/controllers/action'
|
4
4
|
require 'cuprum/rails/controllers/class_methods'
|
5
5
|
|
6
6
|
module Cuprum::Rails::Controllers::ClassMethods
|
@@ -18,8 +18,7 @@ module Cuprum::Rails::Controllers::ClassMethods
|
|
18
18
|
validate_class(action_class, as: 'action class')
|
19
19
|
|
20
20
|
action_name = action_name.intern
|
21
|
-
own_actions[action_name] = Cuprum::Rails::
|
22
|
-
configuration,
|
21
|
+
own_actions[action_name] = Cuprum::Rails::Controllers::Action.new(
|
23
22
|
action_class: action_class,
|
24
23
|
action_name: action_name,
|
25
24
|
member_action: member
|
@@ -28,7 +27,7 @@ module Cuprum::Rails::Controllers::ClassMethods
|
|
28
27
|
define_action(action_name)
|
29
28
|
end
|
30
29
|
|
31
|
-
# @return [Hash<Symbol, Cuprum::Rails::
|
30
|
+
# @return [Hash<Symbol, Cuprum::Rails::Controllers::Action>] the actions
|
32
31
|
# defined for the controller.
|
33
32
|
def actions
|
34
33
|
ancestors
|
@@ -38,18 +37,45 @@ module Cuprum::Rails::Controllers::ClassMethods
|
|
38
37
|
.reduce(&:merge)
|
39
38
|
end
|
40
39
|
|
40
|
+
# @private
|
41
|
+
def apply_request_defaults(request)
|
42
|
+
request.format ||= configuration.default_format
|
43
|
+
end
|
44
|
+
|
45
|
+
# Generates a Cuprum::Rails::Request from a native request.
|
46
|
+
#
|
47
|
+
# Override this method to generate a request subclass.
|
48
|
+
#
|
49
|
+
# @param context [#request] the controller or controller context.
|
50
|
+
# @param options [Hash{Symbol=>Object}] additional options for the request.
|
51
|
+
#
|
52
|
+
# @return [Cuprum::Rails::Request] the generated request.
|
53
|
+
def build_request(context, **options)
|
54
|
+
Cuprum::Rails::Request.build(
|
55
|
+
context: context,
|
56
|
+
request: context.request,
|
57
|
+
**options
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
41
61
|
# @private
|
42
62
|
def own_actions
|
63
|
+
# :nocov:
|
43
64
|
@own_actions ||= {}
|
65
|
+
# :nocov:
|
44
66
|
end
|
45
67
|
|
46
68
|
private
|
47
69
|
|
48
70
|
def define_action(action_name)
|
49
71
|
define_method(action_name) do
|
50
|
-
|
51
|
-
|
52
|
-
|
72
|
+
action = self.class.actions[action_name]
|
73
|
+
request =
|
74
|
+
self
|
75
|
+
.class
|
76
|
+
.build_request(self, member_action: action.member_action?)
|
77
|
+
.tap { |req| self.class.apply_request_defaults(req) }
|
78
|
+
response = action.call(self, request)
|
53
79
|
response.call(self)
|
54
80
|
end
|
55
81
|
end
|
@@ -13,11 +13,40 @@ module Cuprum::Rails::Controllers::ClassMethods
|
|
13
13
|
Cuprum::Rails::Controllers::Configuration.new(self)
|
14
14
|
end
|
15
15
|
|
16
|
+
# @overload default_format
|
17
|
+
# @return [Symbol] the default format for controller requests.
|
18
|
+
#
|
19
|
+
# @overload default_format(format)
|
20
|
+
# Sets the default format for controller requests.
|
21
|
+
#
|
22
|
+
# @param format [String, Symbol] The format to set as default.
|
23
|
+
def default_format(format = nil)
|
24
|
+
if format.nil?
|
25
|
+
return @default_format if @default_format
|
26
|
+
|
27
|
+
return superclass.default_format if controller_class?(superclass)
|
28
|
+
|
29
|
+
return nil
|
30
|
+
end
|
31
|
+
|
32
|
+
validate_name(format, as: 'format')
|
33
|
+
|
34
|
+
@default_format = format.intern
|
35
|
+
end
|
36
|
+
|
16
37
|
# @private
|
17
38
|
def own_responders
|
18
39
|
@own_responders ||= {}
|
19
40
|
end
|
20
41
|
|
42
|
+
# Returns the repository defined for the controller.
|
43
|
+
#
|
44
|
+
# @return [Cuprum::Collections::Repository] the repository containing the
|
45
|
+
# data collections for the application or scope.
|
46
|
+
def repository
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
21
50
|
# Returns the resource defined for the controller.
|
22
51
|
#
|
23
52
|
# Controller subclasses must override this method.
|
@@ -60,5 +89,12 @@ module Cuprum::Rails::Controllers::ClassMethods
|
|
60
89
|
json: Cuprum::Rails::Serializers::Json.default_serializers
|
61
90
|
}
|
62
91
|
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def controller_class?(other)
|
96
|
+
other.singleton_class <
|
97
|
+
Cuprum::Rails::Controllers::ClassMethods::Configuration
|
98
|
+
end
|
63
99
|
end
|
64
100
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/rails/controllers/class_methods'
|
4
|
+
require 'cuprum/rails/controllers/middleware'
|
5
|
+
|
6
|
+
module Cuprum::Rails::Controllers::ClassMethods
|
7
|
+
# Provides a DSL for defining controller middleware.
|
8
|
+
module Middleware
|
9
|
+
# @overload middleware
|
10
|
+
# @return [Array<Cuprum::Rails::Controllers::Middleware>] the configured
|
11
|
+
# middleware for the controller.
|
12
|
+
#
|
13
|
+
# @overload middleware(command, except: [], only: {]})
|
14
|
+
# Defines middleware for the controller.
|
15
|
+
#
|
16
|
+
# @param command [Class, Cuprum::Command] The middleware command.
|
17
|
+
# Middleware commands must take two parameters: a next_command argument,
|
18
|
+
# and a request: keyword.
|
19
|
+
# @param except [Array<String, Symbol>] Action names to exclude. The
|
20
|
+
# middleware will not be applied to actions on this list.
|
21
|
+
# @param only [Array<String, Symbol>] Action names to include If this is
|
22
|
+
# not empty, the middleware will only be applied to actions on this
|
23
|
+
# list.
|
24
|
+
#
|
25
|
+
# @see Cuprum::Middleware
|
26
|
+
def middleware(command = nil, except: [], only: [])
|
27
|
+
unless command.nil?
|
28
|
+
own_middleware <<
|
29
|
+
build_middleware(command: command, except: except, only: only)
|
30
|
+
end
|
31
|
+
|
32
|
+
ancestors
|
33
|
+
.select { |ancestor| ancestor.respond_to?(:own_middleware) }
|
34
|
+
.reverse_each
|
35
|
+
.map(&:own_middleware)
|
36
|
+
.reduce(&:+)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @private
|
40
|
+
def own_middleware
|
41
|
+
@own_middleware ||= []
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def build_middleware(command:, except:, only:)
|
47
|
+
validate_command!(command)
|
48
|
+
validate_action_names!(except, as: 'except')
|
49
|
+
validate_action_names!(only, as: 'only')
|
50
|
+
|
51
|
+
Cuprum::Rails::Controllers::Middleware.new(
|
52
|
+
command: command,
|
53
|
+
except: except,
|
54
|
+
only: only
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
def valid_action_names?(action_names)
|
59
|
+
return false unless action_names.is_a?(Array)
|
60
|
+
|
61
|
+
action_names.all? do |action_name|
|
62
|
+
next false unless action_name.is_a?(String) || action_name.is_a?(Symbol)
|
63
|
+
|
64
|
+
!action_name.empty?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def validate_action_names!(action_names, as:)
|
69
|
+
return if action_names.nil?
|
70
|
+
|
71
|
+
return if valid_action_names?(action_names)
|
72
|
+
|
73
|
+
raise ArgumentError,
|
74
|
+
"#{as} must be a list of action names",
|
75
|
+
caller(1..-1)
|
76
|
+
end
|
77
|
+
|
78
|
+
def validate_command!(command)
|
79
|
+
return if command.is_a?(Cuprum::Command)
|
80
|
+
|
81
|
+
return if command.is_a?(Class) && command < Cuprum::Command
|
82
|
+
|
83
|
+
raise ArgumentError,
|
84
|
+
'command must be an instance of or subclass of Cuprum::Command',
|
85
|
+
caller(1..-1)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -7,13 +7,13 @@ module Cuprum::Rails::Controllers::ClassMethods
|
|
7
7
|
module Validations
|
8
8
|
private
|
9
9
|
|
10
|
-
def validate_class(value, as:)
|
10
|
+
def validate_class(value, as:)
|
11
11
|
return if value.is_a?(Class)
|
12
12
|
|
13
13
|
raise ArgumentError, "#{as} must be a Class", caller(1..-1)
|
14
14
|
end
|
15
15
|
|
16
|
-
def validate_name(value, as:)
|
16
|
+
def validate_name(value, as:)
|
17
17
|
raise ArgumentError, "#{as} can't be blank", caller(1..-1) if value.nil?
|
18
18
|
|
19
19
|
unless value.is_a?(String) || value.is_a?(Symbol)
|
@@ -18,6 +18,20 @@ module Cuprum::Rails::Controllers
|
|
18
18
|
# @return [#resource, #responders] the controller to delegate configuration.
|
19
19
|
attr_reader :controller
|
20
20
|
|
21
|
+
# @!method controller_name
|
22
|
+
# @return [String] the name of the controller.
|
23
|
+
|
24
|
+
# @!method default_format
|
25
|
+
# @return [Symbol] the default format for controller requests.
|
26
|
+
|
27
|
+
# @!method middleware
|
28
|
+
# @return [Array<Cuprum::Rails::Controllers::Middleware>] the middleware
|
29
|
+
# defined for the controller.
|
30
|
+
|
31
|
+
# @!method repository
|
32
|
+
# @return [Cuprum::Collections::Repository] the repository containing the
|
33
|
+
# data collections for the application or scope.
|
34
|
+
|
21
35
|
# @!method resource
|
22
36
|
# @return [Cuprum::Rails::Resource] the resource defined for the
|
23
37
|
# controller.
|
@@ -31,13 +45,27 @@ module Cuprum::Rails::Controllers
|
|
31
45
|
# serializers for converting result values into serialized data.
|
32
46
|
|
33
47
|
def_delegators :@controller,
|
48
|
+
:controller_name,
|
49
|
+
:default_format,
|
50
|
+
:middleware,
|
51
|
+
:repository,
|
34
52
|
:resource,
|
35
53
|
:responders,
|
36
54
|
:serializers
|
37
55
|
|
56
|
+
# Finds the configured middleware for the requested action name.
|
57
|
+
#
|
58
|
+
# @param action_name [Symbol] The name of the action.
|
59
|
+
#
|
60
|
+
# @return [Array<Cuprum::Rails::Controllers::Middleware>] the configured
|
61
|
+
# middleware for the action.
|
62
|
+
def middleware_for(action_name)
|
63
|
+
middleware.select { |item| item.matches?(action_name) }
|
64
|
+
end
|
65
|
+
|
38
66
|
# Finds the configured responder for the requested format.
|
39
67
|
#
|
40
|
-
# @param format [Symbol]
|
68
|
+
# @param format [Symbol] the format to respond to.
|
41
69
|
#
|
42
70
|
# @return [Class] the responder class defined for the format.
|
43
71
|
#
|
@@ -49,5 +77,17 @@ module Cuprum::Rails::Controllers
|
|
49
77
|
"no responder registered for format #{format.inspect}"
|
50
78
|
end
|
51
79
|
end
|
80
|
+
|
81
|
+
# Finds the configured serializers for the requested format.
|
82
|
+
#
|
83
|
+
# @param format [Symbol] the format to respond to.
|
84
|
+
#
|
85
|
+
# @return [Hash<Class, Object>] the serializers for converting result values
|
86
|
+
# into serialized data.
|
87
|
+
def serializers_for(format)
|
88
|
+
serializers
|
89
|
+
.select { |key, _| key.is_a?(Class) }
|
90
|
+
.merge(serializers.fetch(format, {}))
|
91
|
+
end
|
52
92
|
end
|
53
93
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
require 'cuprum/rails/controllers'
|
6
|
+
|
7
|
+
module Cuprum::Rails::Controllers
|
8
|
+
# A configured middleware option for a controller.
|
9
|
+
class Middleware
|
10
|
+
# @param command [Cuprum::Command] The middleware command to wrap the
|
11
|
+
# action or actions.
|
12
|
+
# @param except [Array<Symbol>] A list of action names; the middleware will
|
13
|
+
# not be applied to actions on the list.
|
14
|
+
# @param only [Array<Symbol>] A list of action names; the middleware will
|
15
|
+
# be applied only to actions on the list.
|
16
|
+
def initialize(command:, except: [], only: [])
|
17
|
+
@command = command
|
18
|
+
@except = Set.new(except.map(&:intern))
|
19
|
+
@only = Set.new(only.map(&:intern))
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Cuprum::Middleware] the middleware command to wrap the action or
|
23
|
+
# actions.
|
24
|
+
attr_reader :command
|
25
|
+
|
26
|
+
# @return [Array<Symbol>] a list of action names; the middleware will not be
|
27
|
+
# applied to actions on the list.
|
28
|
+
attr_reader :except
|
29
|
+
|
30
|
+
# @return [Array<Symbol>] a list of action names; the middleware will be
|
31
|
+
# applied only to actions on the list.
|
32
|
+
attr_reader :only
|
33
|
+
|
34
|
+
# @private
|
35
|
+
def ==(other)
|
36
|
+
other.is_a?(Cuprum::Rails::Controllers::Middleware) &&
|
37
|
+
other.command == command &&
|
38
|
+
other.except == except &&
|
39
|
+
other.only == only
|
40
|
+
end
|
41
|
+
|
42
|
+
# Checks if the middleware will be applied to the named action.
|
43
|
+
#
|
44
|
+
# If the middleware defines any :except actions, returns false if the action
|
45
|
+
# name is in the set. If the middleware defines any :only actions, returns
|
46
|
+
# false unless the action name is in the set. Otherwise, returns true.
|
47
|
+
#
|
48
|
+
# @param action_name [Symbol] The name of the action.
|
49
|
+
#
|
50
|
+
# @return [true, false] whether the middleware will be applied.
|
51
|
+
def matches?(action_name)
|
52
|
+
return false unless except.empty? || except.exclude?(action_name)
|
53
|
+
return false unless only.empty? || only.include?(action_name)
|
54
|
+
|
55
|
+
true
|
56
|
+
end
|
57
|
+
alias match? matches?
|
58
|
+
end
|
59
|
+
end
|
@@ -5,6 +5,8 @@ require 'cuprum/rails'
|
|
5
5
|
module Cuprum::Rails
|
6
6
|
# Namespace for controller-specific functionality.
|
7
7
|
module Controllers
|
8
|
+
autoload :Action, 'cuprum/rails/controllers/action'
|
8
9
|
autoload :Configuration, 'cuprum/rails/controllers/configuration'
|
10
|
+
autoload :Middleware, 'cuprum/rails/controllers/middleware'
|
9
11
|
end
|
10
12
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/error'
|
4
|
+
|
5
|
+
require 'cuprum/rails/errors'
|
6
|
+
|
7
|
+
module Cuprum::Rails::Errors
|
8
|
+
# Error class when a parameters hash does not match the expected contract.
|
9
|
+
class InvalidParameters < Cuprum::Error
|
10
|
+
# Short string used to identify the type of error.
|
11
|
+
TYPE = 'cuprum.rails.errors.invalid_parameters'
|
12
|
+
|
13
|
+
# @param errors [Stannum::Errors] the errors returned by the contract.
|
14
|
+
def initialize(errors:)
|
15
|
+
@errors = errors
|
16
|
+
|
17
|
+
super(message: default_message, errors: errors)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Stannum::Errors] the errors returned by the contract.
|
21
|
+
attr_reader :errors
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def as_json_data
|
26
|
+
error_data =
|
27
|
+
errors
|
28
|
+
.group_by_path
|
29
|
+
.to_h do |path, errors|
|
30
|
+
[
|
31
|
+
join_path(path),
|
32
|
+
errors.map { |error| format_error(error) }
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
{ 'errors' => error_data }
|
37
|
+
end
|
38
|
+
|
39
|
+
def default_message
|
40
|
+
"invalid request parameters - #{errors.summary}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def format_error(error)
|
44
|
+
tools.hash_tools.convert_keys_to_strings(error)
|
45
|
+
end
|
46
|
+
|
47
|
+
def join_path(path)
|
48
|
+
path.join('.')
|
49
|
+
end
|
50
|
+
|
51
|
+
def tools
|
52
|
+
SleepingKingStudios::Tools::Toolbelt.instance
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/rails/errors'
|
4
|
+
|
5
|
+
module Cuprum::Rails::Errors
|
6
|
+
# Error class when a database execution error occurs.
|
7
|
+
class InvalidStatement < Cuprum::Error
|
8
|
+
# Short string used to identify the type of error.
|
9
|
+
TYPE = 'cuprum.rails.errors.invalid_statement'
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/rails/errors'
|
4
|
+
|
5
|
+
module Cuprum::Rails::Errors
|
6
|
+
# Error class when a parameters hash does not include the expected keys.
|
7
|
+
class MissingParameter < Cuprum::Error
|
8
|
+
# Short string used to identify the type of error.
|
9
|
+
TYPE = 'cuprum.rails.errors.missing_parameter'
|
10
|
+
|
11
|
+
# @param parameter_name [String, Symbol] the name of the missing parameter.
|
12
|
+
# @param parameters [Hash] the received parameters.
|
13
|
+
def initialize(parameter_name:, parameters:)
|
14
|
+
@parameter_name = parameter_name
|
15
|
+
@parameters = parameters
|
16
|
+
|
17
|
+
super(
|
18
|
+
message: default_message,
|
19
|
+
parameter_name: parameter_name
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [String, Symbol] the name of the missing parameter.
|
24
|
+
attr_reader :parameter_name
|
25
|
+
|
26
|
+
# @return [Hash] the received parameters.
|
27
|
+
attr_reader :parameters
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def as_json_data
|
32
|
+
{
|
33
|
+
'parameter_name' => parameter_name,
|
34
|
+
'parameters' => parameters
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def default_message
|
39
|
+
"missing parameter #{parameter_name.inspect}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/error'
|
4
|
+
|
5
|
+
require 'cuprum/rails/errors'
|
6
|
+
|
7
|
+
module Cuprum::Rails::Errors
|
8
|
+
# Error class when a resource is not correctly configured for an action.
|
9
|
+
class ResourceError < Cuprum::Error
|
10
|
+
# Short string used to identify the type of error.
|
11
|
+
TYPE = 'cuprum.rails.errors.resource_error'
|
12
|
+
|
13
|
+
# @param resource [Cuprum::Rails::Resource] the errored resource.
|
14
|
+
# @param message [String] the message to display, if any.
|
15
|
+
def initialize(resource:, message: nil)
|
16
|
+
@resource = resource
|
17
|
+
|
18
|
+
super(message: generate_message(message), resource: resource)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Cuprum::Rails::Resource] the errored resource.
|
22
|
+
attr_reader :resource
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def as_json_data
|
27
|
+
{
|
28
|
+
'resource' => {
|
29
|
+
'entity_class' => resource.entity_class.to_s,
|
30
|
+
'name' => resource.name.to_s,
|
31
|
+
'qualified_name' => resource.qualified_name.to_s,
|
32
|
+
'singular' => resource.singular?,
|
33
|
+
'singular_name' => resource.singular_name.to_s
|
34
|
+
}
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def generate_message(message = nil)
|
39
|
+
prefix = "invalid resource #{resource.name}"
|
40
|
+
|
41
|
+
return prefix if message.blank?
|
42
|
+
|
43
|
+
"#{prefix} - #{message}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/cuprum/rails/errors.rb
CHANGED
@@ -4,5 +4,10 @@ require 'cuprum/rails'
|
|
4
4
|
|
5
5
|
module Cuprum::Rails
|
6
6
|
# Namespace for custom Cuprum::Rails error classes.
|
7
|
-
module Errors
|
7
|
+
module Errors
|
8
|
+
autoload :InvalidParameters, 'cuprum/rails/errors/invalid_parameters'
|
9
|
+
autoload :InvalidStatement, 'cuprum/rails/errors/invalid_statement'
|
10
|
+
autoload :MissingParameter, 'cuprum/rails/errors/missing_parameter'
|
11
|
+
autoload :ResourceError, 'cuprum/rails/errors/resource_error'
|
12
|
+
end
|
8
13
|
end
|
@@ -28,17 +28,45 @@ module Cuprum::Rails
|
|
28
28
|
|
29
29
|
private
|
30
30
|
|
31
|
+
# :nocov:
|
31
32
|
def map_errors(native_errors:)
|
33
|
+
if Rails.version < '6.1'
|
34
|
+
map_errors_hash(native_errors: native_errors)
|
35
|
+
else
|
36
|
+
map_errors_object(native_errors: native_errors)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def map_errors_hash(native_errors:) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
41
|
+
errors = Stannum::Errors.new
|
42
|
+
details = native_errors.details
|
43
|
+
messages = native_errors.messages
|
44
|
+
|
45
|
+
native_errors.keys.each do |attribute| # rubocop:disable Style/HashEachMethods
|
46
|
+
scoped = attribute == :base ? errors : errors[attribute]
|
47
|
+
|
48
|
+
details[attribute].each.with_index do |hsh, index|
|
49
|
+
message = messages[attribute][index]
|
50
|
+
|
51
|
+
scoped.add(hsh[:error], **hsh.except(:error).merge(message: message))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
errors
|
56
|
+
end
|
57
|
+
|
58
|
+
def map_errors_object(native_errors:)
|
32
59
|
errors = Stannum::Errors.new
|
33
60
|
|
34
61
|
native_errors.each do |error|
|
35
62
|
attribute = error.attribute
|
36
63
|
scoped = attribute == :base ? errors : errors[attribute]
|
37
64
|
|
38
|
-
scoped.add(error.type, message: error.message
|
65
|
+
scoped.add(error.type, **error.options.merge(message: error.message))
|
39
66
|
end
|
40
67
|
|
41
68
|
errors
|
42
69
|
end
|
43
70
|
end
|
71
|
+
# :nocov:
|
44
72
|
end
|
data/lib/cuprum/rails/query.rb
CHANGED
@@ -24,7 +24,7 @@ module Cuprum::Rails
|
|
24
24
|
super()
|
25
25
|
|
26
26
|
default_order = { record_class.primary_key => :asc }
|
27
|
-
@native_query = native_query || record_class.
|
27
|
+
@native_query = native_query || record_class.order(default_order)
|
28
28
|
@record_class = record_class
|
29
29
|
@limit = nil
|
30
30
|
@offset = nil
|
@@ -8,37 +8,24 @@ require 'cuprum/rails/collection'
|
|
8
8
|
module Cuprum::Rails
|
9
9
|
# A repository represents a group of Rails collections.
|
10
10
|
class Repository < Cuprum::Collections::Repository
|
11
|
-
|
12
|
-
#
|
13
|
-
# @param record_class [Class] The ActiveRecord class for the collection.
|
14
|
-
# @param options [Hash] Additional options to pass to Collection.new
|
15
|
-
#
|
16
|
-
# @return [Cuprum::Rails::Collection] the created collection.
|
17
|
-
#
|
18
|
-
# @see Cuprum::Rails::Collection#initialize.
|
19
|
-
def build(record_class:, **options)
|
20
|
-
validate_record_class!(record_class)
|
21
|
-
|
22
|
-
collection = Cuprum::Rails::Collection.new(
|
23
|
-
record_class: record_class,
|
24
|
-
**options
|
25
|
-
)
|
26
|
-
|
27
|
-
add(collection)
|
11
|
+
private
|
28
12
|
|
29
|
-
|
13
|
+
def build_collection(**options)
|
14
|
+
Cuprum::Rails::Collection.new(**options)
|
30
15
|
end
|
31
16
|
|
32
|
-
|
17
|
+
def qualified_name_for(**parameters)
|
18
|
+
Cuprum::Collections::Relation::Disambiguation
|
19
|
+
.resolve_parameters(
|
20
|
+
parameters,
|
21
|
+
entity_class: :record_class,
|
22
|
+
name: :collection_name
|
23
|
+
)
|
24
|
+
.fetch(:qualified_name)
|
25
|
+
end
|
33
26
|
|
34
27
|
def valid_collection?(collection)
|
35
28
|
collection.is_a?(Cuprum::Rails::Collection)
|
36
29
|
end
|
37
|
-
|
38
|
-
def validate_record_class!(record_class)
|
39
|
-
return if record_class.is_a?(Class) && record_class < ActiveRecord::Base
|
40
|
-
|
41
|
-
raise ArgumentError, 'record class must be an ActiveRecord model'
|
42
|
-
end
|
43
30
|
end
|
44
31
|
end
|