sequent 3.0.0 → 3.1.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/bin/sequent +50 -13
- data/lib/sequent/core/aggregate_root.rb +2 -2
- data/lib/sequent/core/base_command_handler.rb +2 -2
- data/lib/sequent/core/helpers/{self_applier.rb → message_handler.rb} +3 -3
- data/lib/sequent/core/projector.rb +10 -2
- data/lib/sequent/core/workflow.rb +2 -2
- data/lib/sequent/generator.rb +2 -0
- data/lib/sequent/generator/command.rb +89 -0
- data/lib/sequent/generator/event.rb +98 -0
- data/lib/sequent/generator/template_command.erb +4 -0
- data/lib/sequent/generator/template_command_handler.erb +5 -0
- data/lib/sequent/generator/template_project/Gemfile +1 -1
- data/lib/sequent/generator/template_project/spec/spec_helper.rb +20 -1
- data/lib/sequent/migrations/view_schema.rb +3 -0
- data/lib/sequent/rake/migration_tasks.rb +32 -8
- data/lib/sequent/sequent.rb +2 -0
- data/lib/sequent/support/database.rb +11 -2
- data/lib/version.rb +1 -1
- metadata +39 -8
- data/lib/sequent/generator/template_project/Gemfile.lock +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60e2be70506a3a7e19fea197f75f1c52e2afe612f95802d4212fc75fac176a65
|
4
|
+
data.tar.gz: c5e8d3769d39168e946b778faa5a9513105b447916bf88f0473509c560a57978
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8299dda5f0dc1119dfe9d8e8bda8fafd0bd3d1aa64216dd965627f72e5db196e5a76661243ab46f1eb5692800e548eb51990d2d566125d3d63a4cd17b4158ea9
|
7
|
+
data.tar.gz: f36ca7aa04c76afc832a36825d518ce8a7378372c46513bd80ebc18f78575c8d057194e95de51b94ca6a8e67b955e5a10189dc0a5fbd678f1e6e0323685af001
|
data/bin/sequent
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require_relative '../lib/sequent/generator'
|
3
3
|
|
4
|
+
command = ARGV[0].to_s.strip
|
5
|
+
args = ARGV[1..-1].map(&:to_s).map(&:strip)
|
6
|
+
abort('Please specify a command. i.e. `sequent new myapp`') if command.empty?
|
7
|
+
|
4
8
|
def new_project(args)
|
5
|
-
|
9
|
+
_args = args.dup
|
10
|
+
name = _args.shift
|
6
11
|
abort('Please specify a directory name. i.e. `sequent new myapp`') if name.empty?
|
7
12
|
|
8
13
|
Sequent::Generator::Project.new(name).execute
|
@@ -15,8 +20,8 @@ def new_project(args)
|
|
15
20
|
|
16
21
|
To finish setting up your app:
|
17
22
|
cd #{name}
|
18
|
-
bundle install
|
19
23
|
bundle exec rake sequent:db:create
|
24
|
+
bundle exec rake sequent:db:create_view_schema
|
20
25
|
bundle exec rake sequent:migrate:online
|
21
26
|
bundle exec rake sequent:migrate:offline
|
22
27
|
|
@@ -28,32 +33,64 @@ def new_project(args)
|
|
28
33
|
sequent generate <aggregate_name>. e.g. sequent generate address
|
29
34
|
|
30
35
|
For more information see:
|
31
|
-
sequent.io
|
36
|
+
https://www.sequent.io
|
32
37
|
|
33
38
|
Happy coding!
|
34
39
|
|
35
40
|
NEXTSTEPS
|
36
41
|
end
|
37
42
|
|
43
|
+
def generate_aggregate(args)
|
44
|
+
_args = args.dup
|
45
|
+
aggregate_name = _args.shift
|
46
|
+
abort('Please specify an aggregate name. i.e. `sequent g aggregate user`') unless args_valid?(aggregate_name)
|
47
|
+
|
48
|
+
Sequent::Generator::Aggregate.new(aggregate_name).execute
|
49
|
+
puts "#{aggregate_name} aggregate has been generated"
|
50
|
+
end
|
51
|
+
|
52
|
+
def generate_command(args)
|
53
|
+
_args = args.dup
|
54
|
+
aggregate_name = _args.shift
|
55
|
+
command_name = _args.shift
|
56
|
+
attrs = _args
|
57
|
+
|
58
|
+
abort('Please specify an aggregate name and command name. i.e. `sequent g command user AddUser`') unless args_valid?(aggregate_name, command_name)
|
59
|
+
Sequent::Generator::Command.new(aggregate_name, command_name, attrs).execute
|
60
|
+
puts "#{command_name} command has been added to #{aggregate_name}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def generate_event(args)
|
64
|
+
_args = args.dup
|
65
|
+
aggregate_name = _args.shift
|
66
|
+
event_name = _args.shift
|
67
|
+
attrs = _args
|
68
|
+
|
69
|
+
abort('Please specify an aggregate name and event name. i.e. `sequent g event user AddUser`') unless args_valid?(aggregate_name, event_name)
|
70
|
+
Sequent::Generator::Event.new(aggregate_name, event_name, attrs).execute
|
71
|
+
puts "#{event_name} event has been added to #{aggregate_name}"
|
72
|
+
end
|
73
|
+
|
38
74
|
def generate(args)
|
39
|
-
|
75
|
+
_args = args.dup
|
76
|
+
entity = _args.shift
|
40
77
|
abort('Please specify a command. i.e. `sequent g aggregate user`') if entity.empty?
|
41
78
|
|
42
79
|
case entity
|
43
80
|
when 'aggregate'
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
81
|
+
generate_aggregate(_args)
|
82
|
+
when 'command'
|
83
|
+
generate_command(_args)
|
84
|
+
when 'event'
|
85
|
+
generate_event(_args)
|
49
86
|
else
|
50
87
|
abort("Unknown argument #{entity} for `generate`. Try `sequent g aggregate user`")
|
51
88
|
end
|
52
89
|
end
|
53
90
|
|
54
|
-
|
55
|
-
|
56
|
-
|
91
|
+
def args_valid?(*args)
|
92
|
+
args.all?(&:present?)
|
93
|
+
end
|
57
94
|
|
58
95
|
case command
|
59
96
|
when 'new'
|
@@ -62,4 +99,4 @@ when 'generate', 'g'
|
|
62
99
|
generate(args)
|
63
100
|
else
|
64
101
|
abort("Unknown command #{command}. Try `sequent new myapp`")
|
65
|
-
end
|
102
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'base64'
|
2
|
-
require_relative 'helpers/
|
2
|
+
require_relative 'helpers/message_handler'
|
3
3
|
require_relative 'stream_record'
|
4
4
|
|
5
5
|
module Sequent
|
@@ -32,7 +32,7 @@ module Sequent
|
|
32
32
|
# +load_from_history+ functionality to be loaded_from_history, meaning a stream of events.
|
33
33
|
#
|
34
34
|
class AggregateRoot
|
35
|
-
include Helpers::
|
35
|
+
include Helpers::MessageHandler
|
36
36
|
include SnapshotConfiguration
|
37
37
|
|
38
38
|
attr_reader :id, :uncommitted_events, :sequence_number, :event_stream
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative 'helpers/
|
1
|
+
require_relative 'helpers/message_handler'
|
2
2
|
require_relative 'helpers/uuid_helper'
|
3
3
|
|
4
4
|
module Sequent
|
@@ -17,7 +17,7 @@ module Sequent
|
|
17
17
|
# end
|
18
18
|
# end
|
19
19
|
class BaseCommandHandler
|
20
|
-
include Sequent::Core::Helpers::
|
20
|
+
include Sequent::Core::Helpers::MessageHandler,
|
21
21
|
Sequent::Core::Helpers::UuidHelper
|
22
22
|
|
23
23
|
protected
|
@@ -3,7 +3,7 @@ module Sequent
|
|
3
3
|
module Helpers
|
4
4
|
##
|
5
5
|
# Creates ability to use DSL like:
|
6
|
-
# class
|
6
|
+
# class MyProjector < Sequent::Projector
|
7
7
|
#
|
8
8
|
# on MyEvent do |event|
|
9
9
|
# do_some_logic
|
@@ -11,10 +11,10 @@ module Sequent
|
|
11
11
|
# end
|
12
12
|
#
|
13
13
|
# You typically do not need to include this module in your classes. If you extend from
|
14
|
-
# Sequent::
|
14
|
+
# Sequent::AggregateRoot, Sequent::Projector, Sequent::Workflow or Sequent::CommandHandler
|
15
15
|
# you will get this functionality for free.
|
16
16
|
#
|
17
|
-
module
|
17
|
+
module MessageHandler
|
18
18
|
|
19
19
|
module ClassMethods
|
20
20
|
def on(*message_classes, &block)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative 'helpers/
|
1
|
+
require_relative 'helpers/message_handler'
|
2
2
|
require_relative './persistors/active_record_persistor'
|
3
3
|
|
4
4
|
module Sequent
|
@@ -42,6 +42,8 @@ module Sequent
|
|
42
42
|
# Example of updating view state, in this case the InvoiceRecord table representing an Invoice
|
43
43
|
#
|
44
44
|
# class InvoiceProjector < Sequent::Core::Projector
|
45
|
+
# manages_tables InvoiceRecord
|
46
|
+
#
|
45
47
|
# on InvoiceCreated do |event|
|
46
48
|
# create_record(
|
47
49
|
# InvoiceRecord,
|
@@ -63,10 +65,12 @@ module Sequent
|
|
63
65
|
#
|
64
66
|
class Projector
|
65
67
|
extend Forwardable
|
66
|
-
include Helpers::
|
68
|
+
include Helpers::MessageHandler
|
67
69
|
include Migratable
|
68
70
|
|
71
|
+
|
69
72
|
def initialize(persistor = Sequent::Core::Persistors::ActiveRecordPersistor.new)
|
73
|
+
ensure_valid!
|
70
74
|
@persistor = persistor
|
71
75
|
end
|
72
76
|
|
@@ -91,6 +95,10 @@ module Sequent
|
|
91
95
|
:execute_sql,
|
92
96
|
:commit
|
93
97
|
|
98
|
+
private
|
99
|
+
def ensure_valid!
|
100
|
+
fail "A Projector must manage at least one table. Did you forget to add `managed_tables` to #{self.class.name}?" if self.class.managed_tables.nil? || self.class.managed_tables.empty?
|
101
|
+
end
|
94
102
|
end
|
95
103
|
end
|
96
104
|
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require_relative 'helpers/
|
1
|
+
require_relative 'helpers/message_handler'
|
2
2
|
|
3
3
|
module Sequent
|
4
4
|
module Core
|
5
5
|
class Workflow
|
6
|
-
include Helpers::
|
6
|
+
include Helpers::MessageHandler
|
7
7
|
|
8
8
|
def execute_commands(*commands)
|
9
9
|
Sequent.configuration.command_service.execute_commands(*commands)
|
data/lib/sequent/generator.rb
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/core_ext/string'
|
4
|
+
require 'erb'
|
5
|
+
require 'parser/current'
|
6
|
+
|
7
|
+
class NoAggregateFound < StandardError; end
|
8
|
+
|
9
|
+
module Sequent
|
10
|
+
module Generator
|
11
|
+
class Command
|
12
|
+
attr_reader :name, :command, :attrs
|
13
|
+
|
14
|
+
def initialize(name, command, attrs)
|
15
|
+
@name = name
|
16
|
+
@command = command
|
17
|
+
@attrs = attrs.map{|a| a.split(':')}
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute
|
21
|
+
ensure_existing_aggregate!
|
22
|
+
add_command_to_aggregate
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def append_command_handler
|
27
|
+
ast = Parser::CurrentRuby.parse(File.read("#{path_to_dir}/#{name_underscored}_command_handler.rb"))
|
28
|
+
target_cursor_position = find_target_cursor_position(ast)
|
29
|
+
|
30
|
+
File.open("#{path_to_dir}/#{name_underscored}_command_handler.rb", 'r+') do |f|
|
31
|
+
f.seek(target_cursor_position, IO::SEEK_SET)
|
32
|
+
lines_to_be_overwritten = f.read
|
33
|
+
f.seek(target_cursor_position, IO::SEEK_SET)
|
34
|
+
f << command_handler_template.result(binding).gsub(/^.+(\s)$/) { |x| x.gsub!($1, '')}
|
35
|
+
f << lines_to_be_overwritten
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def find_target_cursor_position(ast)
|
40
|
+
return unless ast.children.any?
|
41
|
+
|
42
|
+
ast.children.map do |child|
|
43
|
+
return if child.class.to_s != "Parser::AST::Node"
|
44
|
+
return child.loc.expression.end_pos if child.type.to_s == 'block'
|
45
|
+
find_target_cursor_position(child)
|
46
|
+
end.flatten.compact.max
|
47
|
+
end
|
48
|
+
|
49
|
+
def append_command
|
50
|
+
File.open("#{path_to_dir}/commands.rb", "a") { |f| f << command_template.result(binding) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_command_to_aggregate
|
54
|
+
append_command
|
55
|
+
append_command_handler
|
56
|
+
end
|
57
|
+
|
58
|
+
def path
|
59
|
+
@path ||= File.expand_path("lib")
|
60
|
+
end
|
61
|
+
|
62
|
+
def name
|
63
|
+
@name ||= File.basename(path)
|
64
|
+
end
|
65
|
+
|
66
|
+
def name_underscored
|
67
|
+
@name_underscored ||= name.underscore
|
68
|
+
end
|
69
|
+
|
70
|
+
def path_to_dir
|
71
|
+
@path_to_dir ||= "#{path}/#{name_underscored}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def ensure_existing_aggregate!
|
75
|
+
if !File.directory?(path_to_dir) || !File.exist?("#{path_to_dir}/#{name_underscored}_command_handler.rb") || !File.exist?("#{path_to_dir}/commands.rb")
|
76
|
+
raise NoAggregateFound
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def command_template
|
81
|
+
ERB.new(File.read(File.join( File.dirname(__FILE__), 'template_command.erb' )))
|
82
|
+
end
|
83
|
+
|
84
|
+
def command_handler_template
|
85
|
+
ERB.new(File.read(File.join( File.dirname(__FILE__), 'template_command_handler.erb' )))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/core_ext/string'
|
4
|
+
|
5
|
+
class NoAggregateFound < StandardError; end
|
6
|
+
|
7
|
+
module Sequent
|
8
|
+
module Generator
|
9
|
+
class Event
|
10
|
+
attr_reader :name, :event, :attrs
|
11
|
+
|
12
|
+
def initialize(name, event, attrs)
|
13
|
+
@name = name
|
14
|
+
@event = event
|
15
|
+
@attrs = attrs.map{|a| a.split(':')}
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute
|
19
|
+
ensure_existing_aggregate!
|
20
|
+
add_event_to_aggregate
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def append_event
|
26
|
+
File.open("#{path_to_dir}/events.rb", "a") { |f| f << event_template.result(binding) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def append_event_to_domain
|
30
|
+
ast = Parser::CurrentRuby.parse(File.read("#{path_to_dir}/#{name_underscored}.rb"))
|
31
|
+
target_cursor_position = find_target_cursor_position(ast)
|
32
|
+
|
33
|
+
File.open("#{path_to_dir}/#{name_underscored}.rb", 'r+') do |f|
|
34
|
+
f.seek(target_cursor_position, IO::SEEK_SET)
|
35
|
+
lines_to_be_overwritten = f.read
|
36
|
+
f.seek(target_cursor_position, IO::SEEK_SET)
|
37
|
+
f << event_handler_template.result(binding).gsub(/^.+(\s)$/) { |x| x.gsub!($1, '')}
|
38
|
+
f << lines_to_be_overwritten
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_target_cursor_position(ast)
|
43
|
+
return unless ast.children.any?
|
44
|
+
|
45
|
+
ast.children.reverse.map do |child|
|
46
|
+
return if child.class.to_s != "Parser::AST::Node"
|
47
|
+
return child.loc.expression.end_pos if child.type.to_s == 'block'
|
48
|
+
find_target_cursor_position(child)
|
49
|
+
end.flatten.compact.max
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_event_to_aggregate
|
53
|
+
append_event
|
54
|
+
append_event_to_domain
|
55
|
+
end
|
56
|
+
|
57
|
+
def path
|
58
|
+
@path ||= File.expand_path("lib")
|
59
|
+
end
|
60
|
+
|
61
|
+
def name
|
62
|
+
@name ||= File.basename(path)
|
63
|
+
end
|
64
|
+
|
65
|
+
def name_underscored
|
66
|
+
@name_underscored ||= name.underscore
|
67
|
+
end
|
68
|
+
|
69
|
+
def path_to_dir
|
70
|
+
@path_to_dir ||= "#{path}/#{name_underscored}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def ensure_existing_aggregate!
|
74
|
+
if !File.directory?(path_to_dir) || !File.exist?("#{path_to_dir}/#{name_underscored}.rb")
|
75
|
+
raise NoAggregateFound
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def event_template
|
80
|
+
ERB.new <<~EOF
|
81
|
+
|
82
|
+
class <%= event %> < Sequent::Event
|
83
|
+
<% attrs.each do |name, type| %>attrs <%= name.downcase %>: <%= type.downcase.capitalize %><% end %>
|
84
|
+
end
|
85
|
+
EOF
|
86
|
+
end
|
87
|
+
|
88
|
+
def event_handler_template
|
89
|
+
ERB.new <<~EOF
|
90
|
+
\n
|
91
|
+
on <%= event %> do |event|
|
92
|
+
|
93
|
+
end
|
94
|
+
EOF
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -14,16 +14,35 @@ Sequent::Support::Database.establish_connection(db_config)
|
|
14
14
|
Sequent::Support::Database.drop_schema!(Sequent.configuration.view_schema_name)
|
15
15
|
|
16
16
|
Sequent::Migrations::ViewSchema.new(db_config: db_config).create_view_tables
|
17
|
-
|
17
|
+
|
18
|
+
module DomainTests
|
19
|
+
def self.included(base)
|
20
|
+
base.metadata[:domain_tests] = true
|
21
|
+
end
|
22
|
+
end
|
18
23
|
|
19
24
|
RSpec.configure do |config|
|
20
25
|
config.include Sequent::Test::CommandHandlerHelpers
|
26
|
+
config.include DomainTests, file_path: /spec\/lib/
|
27
|
+
|
28
|
+
# Domain tests run with a clean sequent configuration and the in memory FakeEventStore
|
29
|
+
config.around :each, :domain_tests do |example|
|
30
|
+
old_config = Sequent.configuration
|
31
|
+
Sequent::Configuration.reset
|
32
|
+
Sequent.configuration.event_store = Sequent::Test::CommandHandlerHelpers::FakeEventStore.new
|
33
|
+
Sequent.configuration.event_handlers = []
|
34
|
+
example.run
|
35
|
+
ensure
|
36
|
+
Sequent::Configuration.restore(old_config)
|
37
|
+
end
|
21
38
|
|
22
39
|
config.around do |example|
|
23
40
|
Sequent.configuration.aggregate_repository.clear
|
24
41
|
DatabaseCleaner.strategy = :truncation
|
25
42
|
DatabaseCleaner.cleaning do
|
26
43
|
example.run
|
44
|
+
ensure
|
45
|
+
Sequent.configuration.aggregate_repository.clear
|
27
46
|
end
|
28
47
|
end
|
29
48
|
end
|
@@ -110,6 +110,8 @@ module Sequent
|
|
110
110
|
# If anything fails an exception is raised and everything is rolled back
|
111
111
|
#
|
112
112
|
def migrate_online
|
113
|
+
return if Sequent.new_version == current_version
|
114
|
+
|
113
115
|
ensure_version_correct!
|
114
116
|
|
115
117
|
in_view_schema do
|
@@ -344,6 +346,7 @@ module Sequent
|
|
344
346
|
event_stream = Sequent.configuration.event_record_class.where(event_type: event_types)
|
345
347
|
event_stream = event_stream.where("substring(aggregate_id::varchar from 1 for #{LENGTH_OF_SUBSTRING_INDEX_ON_AGGREGATE_ID_IN_EVENT_STORE}) in (?)", aggregate_prefixes)
|
346
348
|
event_stream = event_stream.where("NOT EXISTS (SELECT 1 FROM #{ReplayedIds.table_name} WHERE event_id = event_records.id)") if exclude_already_replayed
|
349
|
+
event_stream = event_stream.where("event_records.created_at > ?", 1.day.ago) if exclude_already_replayed
|
347
350
|
event_stream.order('sequence_number ASC').select('id, event_type, event_json, sequence_number')
|
348
351
|
end
|
349
352
|
|
@@ -17,31 +17,55 @@ module Sequent
|
|
17
17
|
|
18
18
|
namespace :db do
|
19
19
|
|
20
|
-
desc '
|
20
|
+
desc 'Creates the database and initializes the event_store schema for the current env'
|
21
21
|
task :create => ['sequent:init'] do
|
22
22
|
ensure_rack_env_set!
|
23
|
-
sequent_schema = File.join(Sequent.configuration.database_config_directory, "#{Sequent.configuration.event_store_schema_name}.rb")
|
24
|
-
|
25
|
-
fail "File #{sequent_schema} does not exist. Check your Sequent configuration." unless File.exists?(sequent_schema)
|
26
23
|
|
27
24
|
db_config = Sequent::Support::Database.read_config(@env)
|
28
25
|
Sequent::Support::Database.create!(db_config)
|
29
26
|
|
30
|
-
|
31
|
-
Sequent::Support::Database.create_schema(Sequent.configuration.event_store_schema_name)
|
32
|
-
load(sequent_schema)
|
27
|
+
create_event_store(db_config)
|
33
28
|
end
|
34
29
|
|
35
30
|
desc 'Drops the database for the current env'
|
36
31
|
task :drop, [:production] => ['sequent:init'] do |_t, args|
|
37
32
|
ensure_rack_env_set!
|
38
33
|
|
39
|
-
fail "Wont drop db in production unless you whitelist the environment as follows: rake sequent:db:drop[
|
34
|
+
fail "Wont drop db in production unless you whitelist the environment as follows: rake sequent:db:drop[yes_drop_production]" if @env == 'production' && args[:production] != 'yes_drop_production'
|
40
35
|
|
41
36
|
db_config = Sequent::Support::Database.read_config(@env)
|
42
37
|
Sequent::Support::Database.drop!(db_config)
|
43
38
|
end
|
44
39
|
|
40
|
+
desc 'Creates the view schema for the current env'
|
41
|
+
task :create_view_schema => ['sequent:init'] do
|
42
|
+
ensure_rack_env_set!
|
43
|
+
|
44
|
+
db_config = Sequent::Support::Database.read_config(@env)
|
45
|
+
Sequent::Support::Database.establish_connection(db_config)
|
46
|
+
Sequent::Migrations::ViewSchema.new(db_config: db_config).create_view_schema_if_not_exists
|
47
|
+
end
|
48
|
+
|
49
|
+
desc 'Creates the event_store schema for the current env'
|
50
|
+
task :create_event_store => ['sequent:init'] do
|
51
|
+
ensure_rack_env_set!
|
52
|
+
db_config = Sequent::Support::Database.read_config(@env)
|
53
|
+
create_event_store(db_config)
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_event_store(db_config)
|
57
|
+
event_store_schema = Sequent.configuration.event_store_schema_name
|
58
|
+
sequent_schema = File.join(Sequent.configuration.database_config_directory, "#{event_store_schema}.rb")
|
59
|
+
fail "File #{sequent_schema} does not exist. Check your Sequent configuration." unless File.exists?(sequent_schema)
|
60
|
+
|
61
|
+
Sequent::Support::Database.establish_connection(db_config)
|
62
|
+
fail "Schema #{event_store_schema} already exists in the database" if Sequent::Support::Database.schema_exists?(event_store_schema)
|
63
|
+
|
64
|
+
Sequent::Support::Database.create_schema(event_store_schema)
|
65
|
+
Sequent::Support::Database.with_schema_search_path(event_store_schema, db_config, @env) do
|
66
|
+
load(sequent_schema)
|
67
|
+
end
|
68
|
+
end
|
45
69
|
end
|
46
70
|
|
47
71
|
namespace :migrate do
|
data/lib/sequent/sequent.rb
CHANGED
@@ -5,6 +5,7 @@ require_relative 'core/base_command_handler'
|
|
5
5
|
require_relative 'core/aggregate_root'
|
6
6
|
require_relative 'core/projector'
|
7
7
|
require_relative 'core/workflow'
|
8
|
+
require_relative 'core/value_object'
|
8
9
|
require_relative 'generator'
|
9
10
|
|
10
11
|
module Sequent
|
@@ -70,4 +71,5 @@ module Sequent
|
|
70
71
|
AggregateRoot = Sequent::Core::AggregateRoot
|
71
72
|
Projector = Sequent::Core::Projector
|
72
73
|
Workflow = Sequent::Core::Workflow
|
74
|
+
ValueObject = Sequent::Core::ValueObject
|
73
75
|
end
|
@@ -73,12 +73,16 @@ module Sequent
|
|
73
73
|
establish_connection(db_config)
|
74
74
|
end
|
75
75
|
|
76
|
-
def schema_exists?(schema)
|
76
|
+
def self.schema_exists?(schema)
|
77
77
|
ActiveRecord::Base.connection.execute(
|
78
78
|
"SELECT schema_name FROM information_schema.schemata WHERE schema_name like '#{schema}'"
|
79
79
|
).count == 1
|
80
80
|
end
|
81
81
|
|
82
|
+
def schema_exists?(schema)
|
83
|
+
self.class.schema_exists?(schema)
|
84
|
+
end
|
85
|
+
|
82
86
|
def create_schema!(schema)
|
83
87
|
self.class.create_schema(schema)
|
84
88
|
end
|
@@ -93,7 +97,12 @@ module Sequent
|
|
93
97
|
|
94
98
|
def migrate(migrations_path, verbose: true)
|
95
99
|
ActiveRecord::Migration.verbose = verbose
|
96
|
-
ActiveRecord::
|
100
|
+
if ActiveRecord::VERSION::MAJOR >= 5 && ActiveRecord::VERSION::MINOR >= 2
|
101
|
+
ActiveRecord::MigrationContext.new([migrations_path]).up
|
102
|
+
else
|
103
|
+
ActiveRecord::Migrator.migrate(migrations_path)
|
104
|
+
end
|
105
|
+
|
97
106
|
end
|
98
107
|
end
|
99
108
|
end
|
data/lib/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lars Vonk
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2018-
|
15
|
+
date: 2018-09-28 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: activerecord
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: '5.0'
|
24
|
-
- - "
|
24
|
+
- - "<="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '5.2'
|
27
27
|
type: :runtime
|
@@ -31,7 +31,7 @@ dependencies:
|
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '5.0'
|
34
|
-
- - "
|
34
|
+
- - "<="
|
35
35
|
- !ruby/object:Gem::Version
|
36
36
|
version: '5.2'
|
37
37
|
- !ruby/object:Gem::Dependency
|
@@ -41,7 +41,7 @@ dependencies:
|
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: '5.0'
|
44
|
-
- - "
|
44
|
+
- - "<="
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '5.2'
|
47
47
|
type: :runtime
|
@@ -51,7 +51,7 @@ dependencies:
|
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '5.0'
|
54
|
-
- - "
|
54
|
+
- - "<="
|
55
55
|
- !ruby/object:Gem::Version
|
56
56
|
version: '5.2'
|
57
57
|
- !ruby/object:Gem::Dependency
|
@@ -138,6 +138,20 @@ dependencies:
|
|
138
138
|
- - "~>"
|
139
139
|
- !ruby/object:Gem::Version
|
140
140
|
version: '3.2'
|
141
|
+
- !ruby/object:Gem::Dependency
|
142
|
+
name: timecop
|
143
|
+
requirement: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - "~>"
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0.9'
|
148
|
+
type: :development
|
149
|
+
prerelease: false
|
150
|
+
version_requirements: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - "~>"
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0.9'
|
141
155
|
- !ruby/object:Gem::Dependency
|
142
156
|
name: rspec-mocks
|
143
157
|
requirement: !ruby/object:Gem::Requirement
|
@@ -208,6 +222,20 @@ dependencies:
|
|
208
222
|
- - "~>"
|
209
223
|
- !ruby/object:Gem::Version
|
210
224
|
version: 0.14.1
|
225
|
+
- !ruby/object:Gem::Dependency
|
226
|
+
name: parser
|
227
|
+
requirement: !ruby/object:Gem::Requirement
|
228
|
+
requirements:
|
229
|
+
- - "~>"
|
230
|
+
- !ruby/object:Gem::Version
|
231
|
+
version: 2.5.1.0
|
232
|
+
type: :development
|
233
|
+
prerelease: false
|
234
|
+
version_requirements: !ruby/object:Gem::Requirement
|
235
|
+
requirements:
|
236
|
+
- - "~>"
|
237
|
+
- !ruby/object:Gem::Version
|
238
|
+
version: 2.5.1.0
|
211
239
|
description: Sequent is a CQRS and event sourcing framework for Ruby.
|
212
240
|
email:
|
213
241
|
- lars.vonk@gmail.com
|
@@ -247,8 +275,8 @@ files:
|
|
247
275
|
- lib/sequent/core/helpers/equal_support.rb
|
248
276
|
- lib/sequent/core/helpers/helpers.rb
|
249
277
|
- lib/sequent/core/helpers/mergable.rb
|
278
|
+
- lib/sequent/core/helpers/message_handler.rb
|
250
279
|
- lib/sequent/core/helpers/param_support.rb
|
251
|
-
- lib/sequent/core/helpers/self_applier.rb
|
252
280
|
- lib/sequent/core/helpers/string_support.rb
|
253
281
|
- lib/sequent/core/helpers/string_to_value_parsers.rb
|
254
282
|
- lib/sequent/core/helpers/type_conversion_support.rb
|
@@ -269,14 +297,17 @@ files:
|
|
269
297
|
- lib/sequent/core/workflow.rb
|
270
298
|
- lib/sequent/generator.rb
|
271
299
|
- lib/sequent/generator/aggregate.rb
|
300
|
+
- lib/sequent/generator/command.rb
|
301
|
+
- lib/sequent/generator/event.rb
|
272
302
|
- lib/sequent/generator/project.rb
|
273
303
|
- lib/sequent/generator/template_aggregate/template_aggregate.rb
|
274
304
|
- lib/sequent/generator/template_aggregate/template_aggregate/commands.rb
|
275
305
|
- lib/sequent/generator/template_aggregate/template_aggregate/events.rb
|
276
306
|
- lib/sequent/generator/template_aggregate/template_aggregate/template_aggregate.rb
|
277
307
|
- lib/sequent/generator/template_aggregate/template_aggregate/template_aggregate_command_handler.rb
|
308
|
+
- lib/sequent/generator/template_command.erb
|
309
|
+
- lib/sequent/generator/template_command_handler.erb
|
278
310
|
- lib/sequent/generator/template_project/Gemfile
|
279
|
-
- lib/sequent/generator/template_project/Gemfile.lock
|
280
311
|
- lib/sequent/generator/template_project/Rakefile
|
281
312
|
- lib/sequent/generator/template_project/app/projectors/post_projector.rb
|
282
313
|
- lib/sequent/generator/template_project/app/records/post_record.rb
|
@@ -1,72 +0,0 @@
|
|
1
|
-
GIT
|
2
|
-
remote: https://github.com/zilverline/sequent
|
3
|
-
revision: 1e1066279c49d58adbb24f1a1d0e0a7e7bd10a55
|
4
|
-
branch: sequent-30
|
5
|
-
specs:
|
6
|
-
sequent (2.0.0)
|
7
|
-
activemodel (>= 5.0, < 5.2)
|
8
|
-
activerecord (>= 5.0, < 5.2)
|
9
|
-
oj (~> 3.3.9)
|
10
|
-
parallel (~> 1.12.1)
|
11
|
-
pg (~> 1.0)
|
12
|
-
postgresql_cursor (~> 0.6)
|
13
|
-
thread_safe (~> 0.3.5)
|
14
|
-
|
15
|
-
GEM
|
16
|
-
remote: https://rubygems.org/
|
17
|
-
specs:
|
18
|
-
activemodel (5.1.6)
|
19
|
-
activesupport (= 5.1.6)
|
20
|
-
activerecord (5.1.6)
|
21
|
-
activemodel (= 5.1.6)
|
22
|
-
activesupport (= 5.1.6)
|
23
|
-
arel (~> 8.0)
|
24
|
-
activesupport (5.1.6)
|
25
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
26
|
-
i18n (>= 0.7, < 2)
|
27
|
-
minitest (~> 5.1)
|
28
|
-
tzinfo (~> 1.1)
|
29
|
-
arel (8.0.0)
|
30
|
-
concurrent-ruby (1.0.5)
|
31
|
-
database_cleaner (1.7.0)
|
32
|
-
diff-lcs (1.3)
|
33
|
-
i18n (1.0.1)
|
34
|
-
concurrent-ruby (~> 1.0)
|
35
|
-
minitest (5.11.3)
|
36
|
-
oj (3.3.10)
|
37
|
-
parallel (1.12.1)
|
38
|
-
pg (1.0.0)
|
39
|
-
postgresql_cursor (0.6.1)
|
40
|
-
activerecord (>= 3.1.0)
|
41
|
-
rake (12.3.1)
|
42
|
-
rspec (3.7.0)
|
43
|
-
rspec-core (~> 3.7.0)
|
44
|
-
rspec-expectations (~> 3.7.0)
|
45
|
-
rspec-mocks (~> 3.7.0)
|
46
|
-
rspec-core (3.7.1)
|
47
|
-
rspec-support (~> 3.7.0)
|
48
|
-
rspec-expectations (3.7.0)
|
49
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
50
|
-
rspec-support (~> 3.7.0)
|
51
|
-
rspec-mocks (3.7.0)
|
52
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
53
|
-
rspec-support (~> 3.7.0)
|
54
|
-
rspec-support (3.7.1)
|
55
|
-
thread_safe (0.3.6)
|
56
|
-
tzinfo (1.2.5)
|
57
|
-
thread_safe (~> 0.1)
|
58
|
-
|
59
|
-
PLATFORMS
|
60
|
-
ruby
|
61
|
-
|
62
|
-
DEPENDENCIES
|
63
|
-
database_cleaner
|
64
|
-
rake
|
65
|
-
rspec
|
66
|
-
sequent!
|
67
|
-
|
68
|
-
RUBY VERSION
|
69
|
-
ruby 2.5.1p57
|
70
|
-
|
71
|
-
BUNDLED WITH
|
72
|
-
1.16.2
|