sequent 2.1.0 → 3.0.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 +65 -0
- data/db/sequent_schema.rb +9 -8
- data/lib/sequent.rb +3 -0
- data/lib/sequent/configuration.rb +67 -0
- data/lib/sequent/core/aggregate_repository.rb +1 -1
- data/lib/sequent/core/core.rb +2 -2
- data/lib/sequent/core/event_store.rb +2 -2
- data/lib/sequent/core/helpers/attribute_support.rb +3 -0
- data/lib/sequent/core/helpers/self_applier.rb +1 -1
- data/lib/sequent/core/{record_sessions/active_record_session.rb → persistors/active_record_persistor.rb} +21 -19
- data/lib/sequent/core/persistors/persistor.rb +84 -0
- data/lib/sequent/core/persistors/persistors.rb +3 -0
- data/lib/sequent/core/{record_sessions/replay_events_session.rb → persistors/replay_optimized_postgres_persistor.rb} +16 -7
- data/lib/sequent/core/projector.rb +96 -0
- data/lib/sequent/generator.rb +2 -0
- data/lib/sequent/generator/aggregate.rb +71 -0
- data/lib/sequent/generator/project.rb +61 -0
- data/lib/sequent/generator/template_aggregate/template_aggregate.rb +4 -0
- data/lib/sequent/generator/template_aggregate/template_aggregate/commands.rb +2 -0
- data/lib/sequent/generator/template_aggregate/template_aggregate/events.rb +2 -0
- data/lib/sequent/generator/template_aggregate/template_aggregate/template_aggregate.rb +9 -0
- data/lib/sequent/generator/template_aggregate/template_aggregate/template_aggregate_command_handler.rb +5 -0
- data/lib/sequent/generator/template_project/Gemfile +11 -0
- data/lib/sequent/generator/template_project/Gemfile.lock +72 -0
- data/lib/sequent/generator/template_project/Rakefile +12 -0
- data/lib/sequent/generator/template_project/app/projectors/post_projector.rb +22 -0
- data/lib/sequent/generator/template_project/app/records/post_record.rb +2 -0
- data/lib/sequent/generator/template_project/config/initializers/sequent.rb +13 -0
- data/lib/sequent/generator/template_project/db/database.yml +17 -0
- data/lib/sequent/generator/template_project/db/migrations.rb +17 -0
- data/lib/sequent/generator/template_project/db/sequent_schema.rb +51 -0
- data/lib/sequent/generator/template_project/db/tables/post_records.sql +10 -0
- data/lib/sequent/generator/template_project/lib/post.rb +4 -0
- data/lib/sequent/generator/template_project/lib/post/commands.rb +4 -0
- data/lib/sequent/generator/template_project/lib/post/events.rb +14 -0
- data/lib/sequent/generator/template_project/lib/post/post.rb +24 -0
- data/lib/sequent/generator/template_project/lib/post/post_command_handler.rb +5 -0
- data/lib/sequent/generator/template_project/my_app.rb +11 -0
- data/lib/sequent/generator/template_project/spec/app/projectors/post_projector_spec.rb +32 -0
- data/lib/sequent/generator/template_project/spec/lib/post/post_command_handler_spec.rb +20 -0
- data/lib/sequent/generator/template_project/spec/spec_helper.rb +29 -0
- data/lib/sequent/migrations/migrate_events.rb +1 -0
- data/lib/sequent/migrations/migrations.rb +2 -0
- data/lib/sequent/migrations/projectors.rb +18 -0
- data/lib/sequent/migrations/view_schema.rb +364 -0
- data/lib/sequent/rake/migration_tasks.rb +109 -0
- data/lib/sequent/rake/tasks.rb +16 -0
- data/lib/sequent/sequent.rb +53 -13
- data/lib/sequent/support/database.rb +53 -8
- data/lib/sequent/util/printer.rb +16 -0
- data/lib/sequent/util/timer.rb +14 -0
- data/lib/sequent/util/util.rb +2 -0
- data/lib/version.rb +1 -1
- metadata +67 -14
- data/lib/sequent/core/base_event_handler.rb +0 -54
- data/lib/sequent/core/record_sessions/record_sessions.rb +0 -2
@@ -0,0 +1,96 @@
|
|
1
|
+
require_relative 'helpers/self_applier'
|
2
|
+
require_relative './persistors/active_record_persistor'
|
3
|
+
|
4
|
+
module Sequent
|
5
|
+
module Core
|
6
|
+
|
7
|
+
module Migratable
|
8
|
+
module ClassMethods
|
9
|
+
def manages_tables(*tables)
|
10
|
+
@managed_tables = tables
|
11
|
+
end
|
12
|
+
|
13
|
+
def managed_tables
|
14
|
+
@managed_tables
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.projectors
|
19
|
+
Sequent.configuration.event_handlers.select { |x| x.is_a? Migratable }.map(&:class)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(host_class)
|
23
|
+
host_class.extend(ClassMethods)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.none
|
27
|
+
[]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.all
|
31
|
+
Migratable.projectors
|
32
|
+
end
|
33
|
+
|
34
|
+
def managed_tables
|
35
|
+
self.class.managed_tables
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
# Projectors listen to events and update the view state as they see fit.
|
41
|
+
#
|
42
|
+
# Example of updating view state, in this case the InvoiceRecord table representing an Invoice
|
43
|
+
#
|
44
|
+
# class InvoiceProjector < Sequent::Core::Projector
|
45
|
+
# on InvoiceCreated do |event|
|
46
|
+
# create_record(
|
47
|
+
# InvoiceRecord,
|
48
|
+
# recipient: event.recipient,
|
49
|
+
# amount: event.amount
|
50
|
+
# )
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# Please note that the actual storage is abstracted away in the +persistors+.
|
55
|
+
# Due to this abstraction you can not traverse persist or traverse child objects
|
56
|
+
# like you are used to do with ActiveRecord. The following example will not work:
|
57
|
+
#
|
58
|
+
# invoice_record.line_item_records << create_record(LineItemRecord, ...)
|
59
|
+
#
|
60
|
+
# In this case you should simply do:
|
61
|
+
#
|
62
|
+
# create_record(LineItemRecord, invoice_id: invoice_record.aggregate_id)
|
63
|
+
#
|
64
|
+
class Projector
|
65
|
+
extend Forwardable
|
66
|
+
include Helpers::SelfApplier
|
67
|
+
include Migratable
|
68
|
+
|
69
|
+
def initialize(persistor = Sequent::Core::Persistors::ActiveRecordPersistor.new)
|
70
|
+
@persistor = persistor
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.replay_persistor
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def_delegators :@persistor,
|
78
|
+
:update_record,
|
79
|
+
:create_record,
|
80
|
+
:create_records,
|
81
|
+
:create_or_update_record,
|
82
|
+
:get_record!,
|
83
|
+
:get_record,
|
84
|
+
:delete_all_records,
|
85
|
+
:update_all_records,
|
86
|
+
:do_with_records,
|
87
|
+
:do_with_record,
|
88
|
+
:delete_record,
|
89
|
+
:find_records,
|
90
|
+
:last_record,
|
91
|
+
:execute_sql,
|
92
|
+
:commit
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/core_ext/string'
|
4
|
+
|
5
|
+
class TargetAlreadyExists < StandardError; end
|
6
|
+
|
7
|
+
module Sequent
|
8
|
+
module Generator
|
9
|
+
class Aggregate
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
def initialize(name)
|
13
|
+
@name = name
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute
|
17
|
+
ensure_not_used!
|
18
|
+
copy_files
|
19
|
+
rename_files
|
20
|
+
replace_template_aggregate
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def copy_files
|
26
|
+
FileUtils.copy_entry(File.expand_path('template_aggregate', __dir__), path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def rename_files
|
30
|
+
FileUtils.mv("#{path}/template_aggregate.rb", "#{path}/#{name_underscored}.rb")
|
31
|
+
FileUtils.mv("#{path}/template_aggregate", "#{path}/#{name_underscored}")
|
32
|
+
|
33
|
+
FileUtils.mv("#{path}/#{name_underscored}/template_aggregate_command_handler.rb", "#{path}/#{name_underscored}/#{name_underscored}_command_handler.rb")
|
34
|
+
FileUtils.mv("#{path}/#{name_underscored}/template_aggregate.rb", "#{path}/#{name_underscored}/#{name_underscored}.rb")
|
35
|
+
end
|
36
|
+
|
37
|
+
def replace_template_aggregate
|
38
|
+
files = Dir["#{path}/**/*"].select { |f| File.file?(f) }
|
39
|
+
|
40
|
+
files.each do |filename|
|
41
|
+
contents = File.read(filename)
|
42
|
+
contents.gsub!('template_aggregate', name_underscored)
|
43
|
+
contents.gsub!('TemplateAggregate', name_camelized)
|
44
|
+
File.open(filename, 'w') { |f| f.puts contents }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def path
|
49
|
+
@path ||= File.expand_path("lib")
|
50
|
+
end
|
51
|
+
|
52
|
+
def name
|
53
|
+
@name ||= File.basename(path)
|
54
|
+
end
|
55
|
+
|
56
|
+
def name_underscored
|
57
|
+
@name_underscored ||= name.underscore
|
58
|
+
end
|
59
|
+
|
60
|
+
def name_camelized
|
61
|
+
@name_camelized ||= name.camelize
|
62
|
+
end
|
63
|
+
|
64
|
+
def ensure_not_used!
|
65
|
+
if File.directory?("#{path}/#{name_underscored}") || File.exist?("#{path}/#{name_underscored}.rb")
|
66
|
+
raise TargetAlreadyExists
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/core_ext/string'
|
4
|
+
|
5
|
+
module Sequent
|
6
|
+
module Generator
|
7
|
+
class Project
|
8
|
+
def initialize(path_or_name)
|
9
|
+
@path_or_name = path_or_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute
|
13
|
+
make_directory
|
14
|
+
copy_files
|
15
|
+
rename_app_file
|
16
|
+
replace_app_name
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def make_directory
|
22
|
+
FileUtils.mkdir_p(path)
|
23
|
+
end
|
24
|
+
|
25
|
+
def copy_files
|
26
|
+
FileUtils.copy_entry(File.expand_path('template_project', __dir__), path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def rename_app_file
|
30
|
+
FileUtils.mv("#{path}/my_app.rb", "#{path}/#{name_underscored}.rb")
|
31
|
+
end
|
32
|
+
|
33
|
+
def replace_app_name
|
34
|
+
files = Dir["#{path}/**/*"].select { |f| File.file?(f) }
|
35
|
+
|
36
|
+
files.each do |filename|
|
37
|
+
contents = File.read(filename)
|
38
|
+
contents.gsub!('my_app', name_underscored)
|
39
|
+
contents.gsub!('MyApp', name_camelized)
|
40
|
+
File.open(filename, 'w') { |f| f.puts contents }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def path
|
45
|
+
@path ||= File.expand_path(@path_or_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def name
|
49
|
+
@name ||= File.basename(path)
|
50
|
+
end
|
51
|
+
|
52
|
+
def name_underscored
|
53
|
+
@name_underscored ||= name.underscore
|
54
|
+
end
|
55
|
+
|
56
|
+
def name_camelized
|
57
|
+
@name_camelized ||= name.camelize
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,72 @@
|
|
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
|
@@ -0,0 +1,12 @@
|
|
1
|
+
ENV['RACK_ENV'] ||= 'development'
|
2
|
+
|
3
|
+
require './my_app'
|
4
|
+
require 'sequent/rake/migration_tasks'
|
5
|
+
|
6
|
+
Sequent::Rake::MigrationTasks.new.register_tasks!
|
7
|
+
|
8
|
+
task "sequent:migrate:init" => [:db_connect]
|
9
|
+
|
10
|
+
task "db_connect" do
|
11
|
+
Sequent::Support::Database.connect!(ENV['RACK_ENV'])
|
12
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative '../records/post_record'
|
2
|
+
require_relative '../../lib/post/events'
|
3
|
+
|
4
|
+
class PostProjector < Sequent::Projector
|
5
|
+
manages_tables PostRecord
|
6
|
+
|
7
|
+
on PostAdded do |event|
|
8
|
+
create_record(PostRecord, aggregate_id: event.aggregate_id)
|
9
|
+
end
|
10
|
+
|
11
|
+
on PostAuthorChanged do |event|
|
12
|
+
update_all_records(PostRecord, {aggregate_id: event.aggregate_id}, event.attributes.slice(:author))
|
13
|
+
end
|
14
|
+
|
15
|
+
on PostTitleChanged do |event|
|
16
|
+
update_all_records(PostRecord, {aggregate_id: event.aggregate_id}, event.attributes.slice(:title))
|
17
|
+
end
|
18
|
+
|
19
|
+
on PostContentChanged do |event|
|
20
|
+
update_all_records(PostRecord, {aggregate_id: event.aggregate_id}, event.attributes.slice(:content))
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
database: &database
|
2
|
+
adapter: postgresql
|
3
|
+
host: localhost
|
4
|
+
port: 5432
|
5
|
+
timeout: 5000
|
6
|
+
schema_search_path: "sequent_schema, view_schema"
|
7
|
+
|
8
|
+
development:
|
9
|
+
<<: *database
|
10
|
+
pool: 5
|
11
|
+
database: my_app_development
|
12
|
+
|
13
|
+
test:
|
14
|
+
<<: *database
|
15
|
+
pool: 5
|
16
|
+
database: my_app_test
|
17
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'sequent/migrations/projectors'
|
2
|
+
|
3
|
+
VIEW_SCHEMA_VERSION = 1
|
4
|
+
|
5
|
+
class Migrations < Sequent::Migrations::Projectors
|
6
|
+
def self.version
|
7
|
+
VIEW_SCHEMA_VERSION
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.versions
|
11
|
+
{
|
12
|
+
'1' => [
|
13
|
+
PostProjector
|
14
|
+
]
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|