command_service_object 0.6.4 → 1.2.1
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/Gemfile.lock +74 -61
- data/README.md +41 -22
- data/command_service_object.gemspec +2 -1
- data/lib/command_service_object.rb +1 -0
- data/lib/command_service_object/helpers/check_helper.rb +9 -0
- data/lib/command_service_object/version.rb +1 -1
- data/lib/generators/.DS_Store +0 -0
- data/lib/generators/service/command/command_generator.rb +23 -3
- data/lib/generators/service/{test/templates/rspec/command.rb.erb → command/templates/command_spec.rb.erb} +0 -0
- data/lib/generators/service/entity/entity_generator.rb +39 -0
- data/lib/generators/service/entity/templates/entity.rb.erb +9 -0
- data/lib/generators/service/external/external_generator.rb +46 -0
- data/lib/generators/service/external/templates/external.rb.erb +16 -0
- data/lib/generators/service/external/templates/external_spec.rb.erb +12 -0
- data/lib/generators/service/external/templates/external_test.rb.erb +0 -0
- data/lib/generators/service/helper.rb +23 -0
- data/lib/generators/service/install/templates/initializer.rb +5 -0
- data/lib/generators/service/install/templates/services/application_service.rb +57 -16
- data/lib/generators/service/install/templates/services/case_base.rb +4 -0
- data/lib/generators/service/install/templates/services/listener_base.rb +7 -0
- data/lib/generators/service/install/templates/services/query_base.rb +55 -0
- data/lib/generators/service/listener/listener_generator.rb +39 -0
- data/lib/generators/service/listener/templates/listener.rb.erb +11 -0
- data/lib/generators/service/micro/micro_generator.rb +11 -2
- data/lib/generators/service/query/USAGE +8 -0
- data/lib/generators/service/query/query_generator.rb +39 -0
- data/lib/generators/service/query/templates/query.rb.erb +22 -0
- data/lib/generators/service/service_generator.rb +13 -4
- data/lib/generators/service/setup/setup_generator.rb +20 -6
- data/lib/generators/service/setup/templates/doc.md.erb +39 -0
- data/lib/generators/service/usecase/templates/usecase.rb.erb +17 -3
- data/lib/generators/service/{test/templates/rspec/usecase.rb.erb → usecase/templates/usecase_spec.rb.erb} +0 -0
- data/lib/generators/service/usecase/usecase_generator.rb +22 -3
- metadata +40 -15
- data/lib/generators/service/getter/getter_generator.rb +0 -30
- data/lib/generators/service/getter/templates/getter.rb.erb +0 -8
- data/lib/generators/service/policies.rb +0 -5
- data/lib/generators/service/test/USAGE +0 -8
- data/lib/generators/service/test/templates/minitest/usecase.rb.erb +0 -1
- data/lib/generators/service/test/test_generator.rb +0 -72
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative '../setup/setup_generator.rb'
|
2
|
+
require_relative '../helper'
|
3
|
+
|
4
|
+
module Service
|
5
|
+
module Generators
|
6
|
+
class ExternalGenerator < Rails::Generators::NamedBase
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
8
|
+
|
9
|
+
argument :externals, type: :array, default: [], banner: 'external external'
|
10
|
+
|
11
|
+
def create_externals
|
12
|
+
invoke Service::Generators::SetupGenerator, [name]
|
13
|
+
|
14
|
+
externals.each do |m|
|
15
|
+
@external = m.classify
|
16
|
+
create_main(m)
|
17
|
+
create_test(m)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def create_main(m)
|
24
|
+
path = "#{service_path}/externals/#{m.underscore}.rb"
|
25
|
+
template 'external.rb.erb', path
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_test(m)
|
29
|
+
path = "#{spec_path}/externals/#{m.underscore}_spec.rb"
|
30
|
+
template 'external_spec.rb.erb', path
|
31
|
+
end
|
32
|
+
|
33
|
+
def service_name
|
34
|
+
Service::Helper.service_name(name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def service_path
|
38
|
+
Service::Helper.service_path(name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def spec_path
|
42
|
+
Service::Helper.spec_path(name)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module <%= service_name.classify %>::Externals
|
4
|
+
module <%= @external %>
|
5
|
+
extend self
|
6
|
+
|
7
|
+
# Example
|
8
|
+
# def balance(id)
|
9
|
+
# res = http.get("user/:id")
|
10
|
+
# res_as_json = JSON.parse(res.body)
|
11
|
+
#
|
12
|
+
# The return value should only be OpenStruct or Hash Object
|
13
|
+
# OpenStruct.new(user_id: res_as_json[:id], balance: res_as_json[:balance])
|
14
|
+
# end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe <%= service_name.classify %>::Externals::<%= @external %> do
|
6
|
+
# Example
|
7
|
+
# context "when success" do
|
8
|
+
# it 'should be okay?' do
|
9
|
+
# expect(subject.[method_name]).to eql([result])
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
end
|
File without changes
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Service
|
2
|
+
module Helper
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def service_name(arg)
|
6
|
+
if arg.include? "/"
|
7
|
+
root = arg.split("/").first
|
8
|
+
sub_domain = arg.split("/").last
|
9
|
+
"#{root.underscore}_service/#{sub_domain}"
|
10
|
+
else
|
11
|
+
"#{arg.underscore}_service"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def service_path(arg)
|
16
|
+
"app/services/#{service_name(arg)}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def spec_path(arg)
|
20
|
+
"spec/services/#{service_name(arg)}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -2,38 +2,79 @@
|
|
2
2
|
|
3
3
|
class ApplicationService
|
4
4
|
class << self
|
5
|
+
attr_reader :cmd, :usecase, :bm, :result
|
6
|
+
|
5
7
|
def call(cmd)
|
6
|
-
|
8
|
+
@cmd = cmd
|
9
|
+
@bm = Benchmark.measure do
|
10
|
+
raise Errors::InvalidCommand, cmd.class if cmd.invalid?
|
11
|
+
|
12
|
+
@usecase = usecase_class.new(cmd)
|
13
|
+
raise Errors::NotAuthorizedError, cmd.class unless usecase.allowed?
|
7
14
|
|
8
|
-
|
9
|
-
raise Errors::NotAuthorizedError, cmd.class unless usecase.allowed?
|
15
|
+
@result = ServiceResult.new { usecase.call }
|
10
16
|
|
11
|
-
|
17
|
+
rollback if result.error.present?
|
18
|
+
end
|
12
19
|
|
13
|
-
|
20
|
+
log_command
|
14
21
|
result
|
15
22
|
rescue StandardError => e
|
16
|
-
|
17
|
-
ServiceResult.new { raise e }
|
23
|
+
ServiceResult.new { raise e }
|
18
24
|
end
|
19
25
|
|
20
|
-
def rollback
|
26
|
+
def rollback
|
21
27
|
usecase.rollback_micros
|
22
28
|
usecase.rollback
|
23
|
-
log_errors(result.error
|
29
|
+
log_errors(result.error)
|
24
30
|
end
|
25
31
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
32
|
+
private
|
33
|
+
|
34
|
+
def log_command
|
35
|
+
service_logger = ActiveSupport::Logger.new(Rails.root.join('log', 'services.log').to_s)
|
36
|
+
service_logger.formatter = proc do |severity, datetime, progname, msg|
|
37
|
+
"[#{msg['usecase']}] [#{msg['status']}] [#{datetime.to_s(:db)} ##{Process.pid}] -- #{msg['body']}\n"
|
38
|
+
end
|
39
|
+
log_body = result.ok? ? success_log : failure_log
|
40
|
+
|
41
|
+
service_logger.info(log_body)
|
31
42
|
end
|
32
43
|
|
33
|
-
|
44
|
+
def success_log
|
45
|
+
{
|
46
|
+
usecase: "#{service_name}::#{usecase_name}",
|
47
|
+
status: 'success',
|
48
|
+
body: {
|
49
|
+
cmd: cmd.as_json,
|
50
|
+
result: result.value!.as_json,
|
51
|
+
benchmark: bm.as_json
|
52
|
+
}
|
53
|
+
}.as_json
|
54
|
+
end
|
34
55
|
|
35
|
-
def
|
56
|
+
def failure_log
|
57
|
+
{
|
58
|
+
usecase: "#{service_name}::#{usecase_name}",
|
59
|
+
status: 'faild',
|
60
|
+
body: {
|
61
|
+
cmd: cmd.as_json,
|
62
|
+
error: result.error.to_s,
|
63
|
+
benchmark: bm.as_json
|
64
|
+
}
|
65
|
+
}.as_json
|
66
|
+
end
|
67
|
+
|
68
|
+
def usecase_class
|
36
69
|
cmd.class.name.gsub('Commands', 'Usecases').constantize
|
37
70
|
end
|
71
|
+
|
72
|
+
def service_name
|
73
|
+
cmd.class.name.split('::').first
|
74
|
+
end
|
75
|
+
|
76
|
+
def usecase_name
|
77
|
+
cmd.class.name.split('::').last
|
78
|
+
end
|
38
79
|
end
|
39
80
|
end
|
@@ -1,7 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'hutch'
|
4
|
+
|
3
5
|
class CaseBase
|
6
|
+
include CommandServiceObject::Hooks
|
4
7
|
include CommandServiceObject::FailureHelper
|
8
|
+
include CommandServiceObject::CheckHelper
|
5
9
|
|
6
10
|
attr_reader :cmd, :issuer, :right_name
|
7
11
|
alias_attribute :payload, :cmd
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "active_record"
|
2
|
+
|
3
|
+
class QueryBase
|
4
|
+
RelationRequired = Class.new(StandardError)
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
@options = args.extract_options!
|
8
|
+
@relation = args.first || base_relation
|
9
|
+
|
10
|
+
if relation.nil?
|
11
|
+
raise(
|
12
|
+
RelationRequired,
|
13
|
+
"Queries require a base relation defined. Use .queries method to define relation."
|
14
|
+
)
|
15
|
+
elsif !relation.is_a?(ActiveRecord::Relation)
|
16
|
+
raise(
|
17
|
+
RelationRequired,
|
18
|
+
"Queries accept only ActiveRecord::Relation as input"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.call(*args)
|
24
|
+
new(*args).query
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.queries(subject)
|
28
|
+
self.base_relation = subject
|
29
|
+
end
|
30
|
+
|
31
|
+
def base_relation
|
32
|
+
return nil if self.class.base_relation.nil?
|
33
|
+
|
34
|
+
if self.class.base_relation.is_a?(ActiveRecord::Relation)
|
35
|
+
self.class.base_relation
|
36
|
+
elsif self.class.base_relation < ActiveRecord::Base
|
37
|
+
self.class.base_relation.all
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
class << self
|
44
|
+
attr_accessor :base_relation
|
45
|
+
end
|
46
|
+
|
47
|
+
attr_reader :relation, :options
|
48
|
+
|
49
|
+
def query
|
50
|
+
raise(
|
51
|
+
NotImplementedError,
|
52
|
+
"You need to implement #query method which returns ActiveRecord::Relation object"
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative '../setup/setup_generator.rb'
|
2
|
+
require_relative '../helper'
|
3
|
+
|
4
|
+
module Service
|
5
|
+
module Generators
|
6
|
+
class ListenerGenerator < Rails::Generators::NamedBase
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
8
|
+
|
9
|
+
argument :listeners, type: :array, default: [], banner: 'Listener Listener'
|
10
|
+
|
11
|
+
def setup
|
12
|
+
invoke Service::Generators::SetupGenerator, [name]
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_micros
|
16
|
+
listeners.each do |m|
|
17
|
+
@listener = m.classify
|
18
|
+
|
19
|
+
path = "#{service_path}/listeners/#{m.underscore}.rb"
|
20
|
+
template 'listener.rb.erb', path
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def service_name
|
27
|
+
Service::Helper.service_name(name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def service_path
|
31
|
+
Service::Helper.service_path(name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def spec_path
|
35
|
+
Service::Helper.spec_path(name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative '../setup/setup_generator.rb'
|
2
|
+
require_relative '../helper'
|
2
3
|
|
3
4
|
module Service
|
4
5
|
module Generators
|
@@ -15,7 +16,7 @@ module Service
|
|
15
16
|
micros.each do |m|
|
16
17
|
@micro = m.classify
|
17
18
|
|
18
|
-
path = "
|
19
|
+
path = "#{service_path}/usecases/micros/#{m.underscore}.rb"
|
19
20
|
template 'micro.rb.erb', path
|
20
21
|
end
|
21
22
|
end
|
@@ -23,7 +24,15 @@ module Service
|
|
23
24
|
private
|
24
25
|
|
25
26
|
def service_name
|
26
|
-
|
27
|
+
Service::Helper.service_name(name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def service_path
|
31
|
+
Service::Helper.service_path(name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def spec_path
|
35
|
+
Service::Helper.spec_path(name)
|
27
36
|
end
|
28
37
|
end
|
29
38
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative '../setup/setup_generator.rb'
|
2
|
+
require_relative '../helper'
|
3
|
+
|
4
|
+
module Service
|
5
|
+
module Generators
|
6
|
+
class QueryGenerator < Rails::Generators::NamedBase
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
8
|
+
|
9
|
+
argument :queries, type: :array, default: [], banner: 'query query'
|
10
|
+
|
11
|
+
def setup
|
12
|
+
invoke Service::Generators::SetupGenerator, [name]
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_queries
|
16
|
+
queries.each do |m|
|
17
|
+
@query = m.classify
|
18
|
+
|
19
|
+
path = "#{service_path}/queries/#{m.underscore}.rb"
|
20
|
+
template 'query.rb.erb', path
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def service_name
|
27
|
+
Service::Helper.service_name(name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def service_path
|
31
|
+
Service::Helper.service_path(name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def spec_path
|
35
|
+
Service::Helper.spec_path(name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module <%= service_name.classify %>::Queries
|
4
|
+
class <%= @query %> < QueryBase
|
5
|
+
# queries UserService::Models::User
|
6
|
+
|
7
|
+
# Example
|
8
|
+
# def query
|
9
|
+
# map_rows(relation.where(phone: options.fetch(:phone)))
|
10
|
+
# end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# def map_rows(rows)
|
15
|
+
# rows.map { |r| UserService::Views::User.new(r.as_json).to_hash }
|
16
|
+
# end
|
17
|
+
|
18
|
+
# def map_row(r)
|
19
|
+
# UserService::Views::User.new(r.as_json).to_hash
|
20
|
+
# end
|
21
|
+
end
|
22
|
+
end
|