sequent 0.1.10 → 1.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/db/sequent_schema.rb +0 -3
  3. data/lib/sequent/configuration.rb +10 -0
  4. data/lib/sequent/core/aggregate_repository.rb +41 -8
  5. data/lib/sequent/core/aggregate_root.rb +0 -24
  6. data/lib/sequent/core/aggregate_snapshotter.rb +2 -2
  7. data/lib/sequent/core/base_command_handler.rb +2 -6
  8. data/lib/sequent/core/base_event_handler.rb +1 -1
  9. data/lib/sequent/core/command.rb +23 -15
  10. data/lib/sequent/core/command_service.rb +1 -1
  11. data/lib/sequent/core/core.rb +1 -1
  12. data/lib/sequent/core/event.rb +0 -21
  13. data/lib/sequent/core/event_record.rb +11 -1
  14. data/lib/sequent/core/event_store.rb +122 -18
  15. data/lib/sequent/core/ext/ext.rb +20 -0
  16. data/lib/sequent/core/helpers/array_with_type.rb +4 -0
  17. data/lib/sequent/core/helpers/association_validator.rb +22 -7
  18. data/lib/sequent/core/helpers/attribute_support.rb +15 -6
  19. data/lib/sequent/core/helpers/param_support.rb +28 -29
  20. data/lib/sequent/core/helpers/self_applier.rb +4 -3
  21. data/lib/sequent/core/helpers/string_to_value_parsers.rb +10 -3
  22. data/lib/sequent/core/helpers/type_conversion_support.rb +5 -0
  23. data/lib/sequent/core/helpers/uuid_helper.rb +2 -2
  24. data/lib/sequent/core/helpers/value_validators.rb +2 -2
  25. data/lib/sequent/core/random_uuid_generator.rb +9 -0
  26. data/lib/sequent/core/record_sessions/active_record_session.rb +11 -5
  27. data/lib/sequent/core/record_sessions/replay_events_session.rb +138 -108
  28. data/lib/sequent/core/sequent_oj.rb +4 -3
  29. data/lib/sequent/core/stream_record.rb +1 -1
  30. data/lib/sequent/core/transactions/active_record_transaction_provider.rb +1 -1
  31. data/lib/sequent/migrations/migrate_events.rb +22 -15
  32. data/lib/sequent/rake/tasks.rb +102 -0
  33. data/lib/sequent/sequent.rb +4 -0
  34. data/lib/sequent/support.rb +3 -0
  35. data/lib/sequent/support/database.rb +55 -0
  36. data/lib/sequent/support/view_projection.rb +58 -0
  37. data/lib/sequent/support/view_schema.rb +22 -0
  38. data/lib/sequent/test/command_handler_helpers.rb +21 -8
  39. data/lib/sequent/test/event_handler_helpers.rb +7 -3
  40. data/lib/version.rb +1 -1
  41. metadata +54 -9
  42. data/lib/sequent/core/tenant_event_store.rb +0 -24
@@ -4,8 +4,10 @@ module Sequent
4
4
  module Core
5
5
  # small wrapper class to centralize oj and its settings.
6
6
  class Oj
7
-
8
- ::Oj.default_options={mode: :compat}
7
+ ::Oj.default_options = {
8
+ bigdecimal_as_decimal: false,
9
+ mode: :compat,
10
+ }
9
11
 
10
12
  def self.strict_load(json)
11
13
  ::Oj.strict_load(json, {})
@@ -14,7 +16,6 @@ module Sequent
14
16
  def self.dump(obj)
15
17
  ::Oj.dump(obj)
16
18
  end
17
-
18
19
  end
19
20
  end
20
21
  end
@@ -20,7 +20,7 @@ module Sequent
20
20
  validates_presence_of :aggregate_type, :aggregate_id
21
21
  validates_numericality_of :snapshot_threshold, only_integer: true, greater_than: 0, allow_nil: true
22
22
 
23
- has_many :events
23
+ has_many :event_records
24
24
 
25
25
  def event_stream
26
26
  EventStream.new(aggregate_type: aggregate_type, aggregate_id: aggregate_id, snapshot_threshold: snapshot_threshold, stream_record_id: id)
@@ -4,7 +4,7 @@ module Sequent
4
4
 
5
5
  class ActiveRecordTransactionProvider
6
6
  def transactional
7
- ActiveRecord::Base.transaction do
7
+ ActiveRecord::Base.transaction(requires_new: true) do
8
8
  yield
9
9
  end
10
10
  end
@@ -31,26 +31,33 @@ module Sequent
31
31
  #
32
32
  # @param current_version The current version of the application. E.g. 10
33
33
  # @param new_version The version to migrate to. E.g. 11
34
- # @param &after_migration_block an optional block to run after the migrations run. E.g. close resources
34
+ # @param &after_migration_block an optional block (with the current upgrade version as param) to run after the migrations run. E.g. close resources
35
35
  #
36
36
  def execute_migrations(current_version, new_version, &after_migration_block)
37
- if current_version != new_version and current_version > 0
38
- ((current_version + 1)..new_version).each do |upgrade_to_version|
39
- migration_class = begin
40
- Class.const_get("Database::MigrateToVersion#{upgrade_to_version}")
41
- rescue NameError
42
- nil
43
- end
44
- if migration_class
45
- begin
46
- migration_class.new(@env).migrate
47
- ensure
48
- after_migration_block.call if after_migration_block
49
- end
50
- end
37
+ migrations(current_version, new_version).each do |migration_class|
38
+ migration = migration_class.new(@env)
39
+ begin
40
+ migration.migrate
41
+ ensure
42
+ yield(migration.version) if block_given?
51
43
  end
52
44
  end
53
45
  end
46
+
47
+ def migrations(current_version, new_version)
48
+ return [] if current_version == 0
49
+ ((current_version + 1)..new_version).map do |upgrade_to_version|
50
+ begin
51
+ Class.const_get("Database::MigrateToVersion#{upgrade_to_version}")
52
+ rescue NameError
53
+ nil
54
+ end
55
+ end.compact
56
+ end
57
+
58
+ def has_migrations?(current_version, new_version)
59
+ migrations(current_version, new_version).any?
60
+ end
54
61
  end
55
62
  end
56
63
  end
@@ -0,0 +1,102 @@
1
+ require 'active_record'
2
+ require 'rake'
3
+ require 'rake/tasklib'
4
+
5
+ require 'sequent/support'
6
+
7
+ module Sequent
8
+ module Rake
9
+ class Tasks < ::Rake::TaskLib
10
+ include ::Rake::DSL
11
+
12
+ DEFAULT_OPTIONS = {
13
+ migrations_path: 'db/migrate',
14
+ event_store_schema: 'public'
15
+ }
16
+
17
+ attr_reader :options
18
+
19
+ def initialize(options)
20
+ @options = DEFAULT_OPTIONS.merge(options)
21
+ end
22
+
23
+ def register!
24
+ register_db_tasks!
25
+ register_view_schema_tasks!
26
+ end
27
+
28
+ def register_db_tasks!
29
+ namespace :db do
30
+ desc 'Create the database'
31
+ task :create do
32
+ current_environments.each do |env|
33
+ env_db = db_config(env)
34
+ puts "Create database #{env_db['database']}"
35
+ Sequent::Support::Database.create!(env_db)
36
+ end
37
+ end
38
+
39
+ desc 'Drop the database'
40
+ task :drop do
41
+ current_environments.each do |env|
42
+ env_db = db_config(env)
43
+ puts "Drop database #{env_db['database']}"
44
+ Sequent::Support::Database.drop!(env_db)
45
+ end
46
+ end
47
+
48
+ task :establish_connection do
49
+ env_db = db_config(options.fetch(:environment))
50
+ Sequent::Support::Database.establish_connection(env_db)
51
+ end
52
+
53
+ desc 'Migrate the database'
54
+ task migrate: :establish_connection do
55
+ database.create_schema!(options.fetch(:event_store_schema))
56
+ database.migrate(options.fetch(:migrations_path))
57
+ end
58
+ end
59
+ end
60
+
61
+ def register_view_schema_tasks!
62
+ namespace :view_schema do
63
+ desc 'Build the view schema'
64
+ task build: :'db:establish_connection' do
65
+ if database.schema_exists?(view_projection.schema_name)
66
+ puts "View version #{view_projection.version} already exists; no need to build it"
67
+ else
68
+ database.create_schema!(view_projection.schema_name)
69
+ view_projection.build!
70
+ end
71
+ end
72
+
73
+ desc 'Drop the view schema'
74
+ task drop: :'db:establish_connection' do
75
+ database.drop_schema!(view_projection.schema_name)
76
+ end
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def current_environments
83
+ environment = options.fetch(:environment)
84
+ envs = [environment]
85
+ envs << 'test' if environment == 'development'
86
+ envs
87
+ end
88
+
89
+ def database
90
+ @database ||= Sequent::Support::Database.new
91
+ end
92
+
93
+ def db_config(environment)
94
+ options.fetch(:db_config_supplier)[environment] or fail "No database config for #{environment}"
95
+ end
96
+
97
+ def view_projection
98
+ options.fetch(:view_projection)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -5,6 +5,10 @@ require_relative 'configuration'
5
5
  require 'logger'
6
6
 
7
7
  module Sequent
8
+ def self.new_uuid
9
+ Sequent.configuration.uuid_generator.uuid
10
+ end
11
+
8
12
  def self.logger
9
13
  @logger ||= Logger.new(STDOUT).tap {|l| l.level = Logger::INFO }
10
14
  end
@@ -0,0 +1,3 @@
1
+ require_relative 'support/database'
2
+ require_relative 'support/view_projection'
3
+ require_relative 'support/view_schema'
@@ -0,0 +1,55 @@
1
+ module Sequent
2
+ module Support
3
+ # Offers support operations for a postgres database.
4
+ #
5
+ # Class methods do establish their own database connections (and therefore
6
+ # take in a database configuration). Instance methods assume that a database
7
+ # connection yet is established.
8
+ class Database
9
+ attr_reader :db_config
10
+
11
+ def self.create!(db_config)
12
+ ActiveRecord::Base.establish_connection(db_config.merge('database' => 'postgres'))
13
+ ActiveRecord::Base.connection.create_database(db_config['database'])
14
+ end
15
+
16
+ def self.drop!(db_config)
17
+ ActiveRecord::Base.establish_connection(db_config.merge('database' => 'postgres'))
18
+ ActiveRecord::Base.connection.drop_database(db_config['database'])
19
+ end
20
+
21
+ def self.establish_connection(db_config)
22
+ ActiveRecord::Base.establish_connection(db_config)
23
+ end
24
+
25
+ def self.disconnect!
26
+ ActiveRecord::Base.connection_pool.disconnect!
27
+ end
28
+
29
+ def schema_exists?(schema)
30
+ ActiveRecord::Base.connection.execute(
31
+ "SELECT schema_name FROM information_schema.schemata WHERE schema_name like '#{schema}'"
32
+ ).count == 1
33
+ end
34
+
35
+ def create_schema!(schema)
36
+ sql = "CREATE SCHEMA IF NOT EXISTS #{schema}"
37
+ if user = ActiveRecord::Base.connection_config[:username]
38
+ sql += " AUTHORIZATION #{user}"
39
+ end
40
+ ActiveRecord::Base.connection.execute(sql)
41
+ end
42
+
43
+ def drop_schema!(schema)
44
+ ActiveRecord::Base.connection.execute(
45
+ "DROP SCHEMA IF EXISTS #{schema} CASCADE"
46
+ )
47
+ end
48
+
49
+ def migrate(migrations_path, verbose: true)
50
+ ActiveRecord::Migration.verbose = verbose
51
+ ActiveRecord::Migrator.migrate(migrations_path)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,58 @@
1
+ require 'postgresql_cursor'
2
+
3
+ module Sequent
4
+ module Support
5
+ class ViewProjection
6
+ attr_reader :name, :version, :schema_definition
7
+ def initialize(options)
8
+ @name = options.fetch(:name)
9
+ @version = options.fetch(:version)
10
+ @schema_definition = options.fetch(:definition)
11
+ @replay_event_handlers = options.fetch(:event_handlers)
12
+ end
13
+
14
+ def build!
15
+ with_default_configuration do
16
+ Sequent.configuration.event_handlers = @replay_event_handlers
17
+
18
+ load schema_definition
19
+ event_store = Sequent.configuration.event_store
20
+ ordering = Events::ORDERED_BY_STREAM
21
+ event_store.replay_events_from_cursor(
22
+ block_size: 10_000,
23
+ get_events: ->() { ordering[event_store] }
24
+ )
25
+ end
26
+ end
27
+
28
+ def schema_name
29
+ "#{name}_#{version}"
30
+ end
31
+
32
+ private
33
+
34
+ def with_default_configuration
35
+ original_configuration = Sequent.configuration
36
+ Sequent::Configuration.reset
37
+ yield
38
+ Sequent::Configuration.restore(original_configuration)
39
+ end
40
+ end
41
+
42
+ module Events
43
+ extend ActiveRecord::ConnectionAdapters::Quoting
44
+
45
+ ORDERED_BY_STREAM = lambda do |event_store|
46
+ event_records = quote_table_name(event_store.event_record_class.table_name)
47
+ stream_records = quote_table_name(event_store.stream_record_class.table_name)
48
+ snapshot_event_type = quote(event_store.snapshot_event_class)
49
+
50
+ event_store.event_record_class
51
+ .select("event_type, event_json")
52
+ .joins("INNER JOIN #{stream_records} ON #{event_records}.stream_record_id = #{stream_records}.id")
53
+ .where("event_type <> #{snapshot_event_type}")
54
+ .order!("#{stream_records}.id, #{event_records}.sequence_number")
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,22 @@
1
+ module Sequent
2
+ module Support
3
+ class ViewSchema < ActiveRecord::Schema
4
+ def define(info, &block)
5
+ view_projection = info[:view_projection]
6
+ switch_to_schema(view_projection) if view_projection
7
+ super
8
+ ensure
9
+ switch_back_to_original_schema if view_projection
10
+ end
11
+
12
+ def switch_to_schema(view_projection)
13
+ @original_schema_search_path = connection.schema_search_path
14
+ connection.schema_search_path = view_projection.schema_name
15
+ end
16
+
17
+ def switch_back_to_original_schema
18
+ connection.schema_search_path = @original_schema_search_path
19
+ end
20
+ end
21
+ end
22
+ end
@@ -44,9 +44,17 @@ module Sequent
44
44
  end
45
45
 
46
46
  def load_events(aggregate_id)
47
- event_stream = @event_streams[aggregate_id]
48
- return nil unless event_stream
49
- [event_stream, deserialize_events(@all_events[aggregate_id])]
47
+ load_events_for_aggregates([aggregate_id])[0]
48
+ end
49
+
50
+ def load_events_for_aggregates(aggregate_ids)
51
+ return [] if aggregate_ids.none?
52
+
53
+ aggregate_ids.map do |aggregate_id|
54
+ @event_streams[aggregate_id]
55
+ end.compact.map do |event_stream|
56
+ [event_stream, deserialize_events(@all_events[event_stream.aggregate_id])]
57
+ end
50
58
  end
51
59
 
52
60
  def find_event_stream(aggregate_id)
@@ -119,16 +127,21 @@ module Sequent
119
127
 
120
128
  def when_command command
121
129
  raise "@command_handler is mandatory when using the #{self.class}" unless @command_handler
122
- raise "Command handler #{@command_handler} cannot handle command #{command}, please configure the command type (forgot an include in the command class?)" unless @command_handler.handles_message?(command)
130
+ raise "Command handler #{@command_handler} cannot handle command #{command}, please configure the command type (forgot an include in the command class?)" unless @command_handler.class.handles_message?(command)
123
131
  @command_handler.handle_message(command)
124
132
  @repository.commit(command)
125
133
  @repository.clear
126
134
  end
127
135
 
128
- def then_events *events
129
- expect(@event_store.stored_events.map(&:class)).to eq(events.flatten(1).map(&:class))
130
- @event_store.stored_events.zip(events.flatten(1)).each do |actual, expected|
131
- expect(Sequent::Core::Oj.strict_load(Sequent::Core::Oj.dump(actual.payload))).to eq(Sequent::Core::Oj.strict_load(Sequent::Core::Oj.dump(expected.payload))) if expected
136
+ def then_events(*expected_events)
137
+ expected_classes = expected_events.flatten(1).map { |event| event.class == Class ? event : event.class }
138
+ expect(@event_store.stored_events.map(&:class)).to eq(expected_classes)
139
+
140
+ @event_store.stored_events.zip(expected_events.flatten(1)).each_with_index do |(actual, expected), index|
141
+ next if expected.class == Class
142
+ _actual = Sequent::Core::Oj.strict_load(Sequent::Core::Oj.dump(actual.payload))
143
+ _expected = Sequent::Core::Oj.strict_load(Sequent::Core::Oj.dump(expected.payload))
144
+ expect(_actual).to eq(_expected), "#{index+1}th Event of type #{actual.class} not equal\nexpected: #{_expected.inspect}\n got: #{_actual.inspect}" if expected
132
145
  end
133
146
  end
134
147
 
@@ -39,9 +39,12 @@ module Sequent
39
39
  end
40
40
  end
41
41
 
42
- def then_events *events
43
- expect(@event_store.stored_events.map(&:class)).to eq(events.flatten(1).map(&:class))
44
- @event_store.stored_events.zip(events.flatten(1)).each do |actual, expected|
42
+ def then_events(*expected_events)
43
+ expected_classes = expected_events.flatten(1).map { |event| event.class == Class ? event : event.class }
44
+ expect(@event_store.stored_events.map(&:class)).to eq(expected_classes)
45
+
46
+ @event_store.stored_events.zip(expected_events.flatten(1)).each do |actual, expected|
47
+ next if expected.class == Class
45
48
  expect(Sequent::Core::Oj.strict_load(Sequent::Core::Oj.dump(actual.payload))).to eq(Sequent::Core::Oj.strict_load(Sequent::Core::Oj.dump(expected.payload))) if expected
46
49
  end
47
50
  end
@@ -58,6 +61,7 @@ module Sequent
58
61
  recorded = fake_command_service.recorded_commands
59
62
  expect(recorded.map(&:class)).to eq(commands.flatten(1).map(&:class))
60
63
  expect(fake_command_service.recorded_commands).to eq(commands.flatten(1))
64
+ expect(recorded).to all(be_valid)
61
65
  end
62
66
 
63
67
  def self.included(spec)
@@ -1,3 +1,3 @@
1
1
  module Sequent
2
- VERSION = '0.1.10'
2
+ VERSION = '1.0.0'
3
3
  end
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: 0.1.10
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lars Vonk
@@ -10,36 +10,48 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-10-12 00:00:00.000000000 Z
13
+ date: 2017-06-30 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - "~>"
19
+ - - ">="
20
20
  - !ruby/object:Gem::Version
21
21
  version: '4.0'
22
+ - - "<"
23
+ - !ruby/object:Gem::Version
24
+ version: '5.2'
22
25
  type: :runtime
23
26
  prerelease: false
24
27
  version_requirements: !ruby/object:Gem::Requirement
25
28
  requirements:
26
- - - "~>"
29
+ - - ">="
27
30
  - !ruby/object:Gem::Version
28
31
  version: '4.0'
32
+ - - "<"
33
+ - !ruby/object:Gem::Version
34
+ version: '5.2'
29
35
  - !ruby/object:Gem::Dependency
30
36
  name: activemodel
31
37
  requirement: !ruby/object:Gem::Requirement
32
38
  requirements:
33
- - - "~>"
39
+ - - ">="
34
40
  - !ruby/object:Gem::Version
35
41
  version: '4.0'
42
+ - - "<"
43
+ - !ruby/object:Gem::Version
44
+ version: '5.2'
36
45
  type: :runtime
37
46
  prerelease: false
38
47
  version_requirements: !ruby/object:Gem::Requirement
39
48
  requirements:
40
- - - "~>"
49
+ - - ">="
41
50
  - !ruby/object:Gem::Version
42
51
  version: '4.0'
52
+ - - "<"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.2'
43
55
  - !ruby/object:Gem::Dependency
44
56
  name: pg
45
57
  requirement: !ruby/object:Gem::Requirement
@@ -54,20 +66,34 @@ dependencies:
54
66
  - - "~>"
55
67
  - !ruby/object:Gem::Version
56
68
  version: '0.18'
69
+ - !ruby/object:Gem::Dependency
70
+ name: postgresql_cursor
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.6'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.6'
57
83
  - !ruby/object:Gem::Dependency
58
84
  name: oj
59
85
  requirement: !ruby/object:Gem::Requirement
60
86
  requirements:
61
87
  - - "~>"
62
88
  - !ruby/object:Gem::Version
63
- version: '2.10'
89
+ version: 2.17.5
64
90
  type: :runtime
65
91
  prerelease: false
66
92
  version_requirements: !ruby/object:Gem::Requirement
67
93
  requirements:
68
94
  - - "~>"
69
95
  - !ruby/object:Gem::Version
70
- version: '2.10'
96
+ version: 2.17.5
71
97
  - !ruby/object:Gem::Dependency
72
98
  name: thread_safe
73
99
  requirement: !ruby/object:Gem::Requirement
@@ -152,6 +178,20 @@ dependencies:
152
178
  - - "~>"
153
179
  - !ruby/object:Gem::Version
154
180
  version: '0.10'
181
+ - !ruby/object:Gem::Dependency
182
+ name: simplecov
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: 0.14.1
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: 0.14.1
155
195
  description: Sequent is a CQRS and event sourcing framework for Ruby.
156
196
  email:
157
197
  - lars.vonk@gmail.com
@@ -194,13 +234,13 @@ files:
194
234
  - lib/sequent/core/helpers/type_conversion_support.rb
195
235
  - lib/sequent/core/helpers/uuid_helper.rb
196
236
  - lib/sequent/core/helpers/value_validators.rb
237
+ - lib/sequent/core/random_uuid_generator.rb
197
238
  - lib/sequent/core/record_sessions/active_record_session.rb
198
239
  - lib/sequent/core/record_sessions/record_sessions.rb
199
240
  - lib/sequent/core/record_sessions/replay_events_session.rb
200
241
  - lib/sequent/core/sequent_oj.rb
201
242
  - lib/sequent/core/snapshots.rb
202
243
  - lib/sequent/core/stream_record.rb
203
- - lib/sequent/core/tenant_event_store.rb
204
244
  - lib/sequent/core/transactions/active_record_transaction_provider.rb
205
245
  - lib/sequent/core/transactions/no_transactions.rb
206
246
  - lib/sequent/core/transactions/transactions.rb
@@ -208,7 +248,12 @@ files:
208
248
  - lib/sequent/core/workflow.rb
209
249
  - lib/sequent/migrations/migrate_events.rb
210
250
  - lib/sequent/migrations/migrations.rb
251
+ - lib/sequent/rake/tasks.rb
211
252
  - lib/sequent/sequent.rb
253
+ - lib/sequent/support.rb
254
+ - lib/sequent/support/database.rb
255
+ - lib/sequent/support/view_projection.rb
256
+ - lib/sequent/support/view_schema.rb
212
257
  - lib/sequent/test.rb
213
258
  - lib/sequent/test/command_handler_helpers.rb
214
259
  - lib/sequent/test/event_handler_helpers.rb