rails_event_store_active_record 1.3.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +1 -0
  3. data/Gemfile +5 -10
  4. data/Gemfile.lock +245 -0
  5. data/Gemfile.rails_5_0 +13 -0
  6. data/Gemfile.rails_5_0.lock +217 -0
  7. data/Gemfile.rails_5_1 +13 -0
  8. data/Gemfile.rails_5_1.lock +217 -0
  9. data/Gemfile.rails_5_2 +13 -0
  10. data/Gemfile.rails_5_2.lock +225 -0
  11. data/Gemfile.rails_6_0 +13 -0
  12. data/Gemfile.rails_6_0.lock +241 -0
  13. data/Makefile +8 -15
  14. data/lib/rails_event_store_active_record/event.rb +1 -1
  15. data/lib/rails_event_store_active_record/event_repository.rb +45 -43
  16. data/lib/rails_event_store_active_record/event_repository_reader.rb +101 -37
  17. data/lib/rails_event_store_active_record/generators/{limit_for_event_id_generator.rb → add_valid_at_generator.rb} +2 -2
  18. data/lib/rails_event_store_active_record/generators/{index_by_event_type_generator.rb → created_at_precision_generator.rb} +2 -2
  19. data/lib/rails_event_store_active_record/generators/{binary_data_and_metadata_generator.rb → no_global_stream_entries_generator.rb} +2 -4
  20. data/lib/rails_event_store_active_record/generators/templates/add_valid_at_template.rb +14 -0
  21. data/lib/rails_event_store_active_record/generators/templates/create_event_store_events_template.rb +15 -9
  22. data/lib/rails_event_store_active_record/generators/templates/created_at_precision_template.rb +45 -0
  23. data/lib/rails_event_store_active_record/generators/templates/no_global_stream_entries_template.rb +59 -0
  24. data/lib/rails_event_store_active_record/index_violation_detector.rb +33 -18
  25. data/lib/rails_event_store_active_record/version.rb +1 -1
  26. data/lib/rails_event_store_active_record/with_abstract_base_class.rb +39 -0
  27. data/lib/rails_event_store_active_record/with_default_models.rb +9 -0
  28. data/lib/rails_event_store_active_record.rb +5 -3
  29. data/rails_event_store_active_record.gemspec +1 -3
  30. metadata +23 -13
  31. data/bin/console +0 -14
  32. data/bin/setup +0 -7
  33. data/lib/rails_event_store_active_record/generators/templates/binary_data_and_metadata_template.rb +0 -35
  34. data/lib/rails_event_store_active_record/generators/templates/index_by_event_type_template.rb +0 -7
  35. data/lib/rails_event_store_active_record/generators/templates/limit_for_event_id_template.rb +0 -8
data/Makefile CHANGED
@@ -1,9 +1,15 @@
1
1
  GEM_VERSION = $(shell cat ../RES_VERSION)
2
2
  GEM_NAME = rails_event_store_active_record
3
3
  REQUIRE = $(GEM_NAME)
4
- IGNORE = RailsEventStoreActiveRecord::IndexViolationDetector\#detect \
4
+ IGNORE = RailsEventStoreActiveRecord::IndexViolationDetector\#initialize \
5
+ RailsEventStoreActiveRecord::IndexViolationDetector\#detect \
6
+ RailsEventStoreActiveRecord::IndexViolationDetector\#detect_mysql \
7
+ RailsEventStoreActiveRecord::IndexViolationDetector\#detect_postgres \
5
8
  RailsEventStoreActiveRecord::PgLinearizedEventRepository* \
6
- RailsEventStoreActiveRecord::EventRepository\#update_messages
9
+ RailsEventStoreActiveRecord::EventRepository\#update_messages \
10
+ RailsEventStoreActiveRecord::WithAbstractBaseClass\#build_event_klass \
11
+ RailsEventStoreActiveRecord::WithAbstractBaseClass\#build_stream_klass
12
+
7
13
  SUBJECT ?= RailsEventStoreActiveRecord*
8
14
  DATABASE_URL ?= sqlite3::memory:
9
15
 
@@ -13,16 +19,3 @@ include ../support/make/mutant.mk
13
19
  include ../support/make/gem.mk
14
20
  include ../support/make/help.mk
15
21
 
16
- install: install-gemfiles
17
-
18
- remove-lock: remove-lockfiles
19
-
20
- install-gemfiles:
21
- @BUNDLE_GEMFILE=../support/bundler/Gemfile.0_33_0 bundle check || BUNDLE_GEMFILE=../support/bundler/Gemfile.0_33_0 bundle install
22
- @BUNDLE_GEMFILE=../support/bundler/Gemfile.0_34_0 bundle check || BUNDLE_GEMFILE=../support/bundler/Gemfile.0_34_0 bundle install
23
- @BUNDLE_GEMFILE=../support/bundler/Gemfile.0_35_0 bundle check || BUNDLE_GEMFILE=../support/bundler/Gemfile.0_35_0 bundle install
24
-
25
- remove-lockfiles:
26
- -rm ../support/bundler/Gemfile.0_33_0.lock
27
- -rm ../support/bundler/Gemfile.0_34_0.lock
28
- -rm ../support/bundler/Gemfile.0_35_0.lock
@@ -11,6 +11,6 @@ module RailsEventStoreActiveRecord
11
11
  class EventInStream < ::ActiveRecord::Base
12
12
  self.primary_key = :id
13
13
  self.table_name = 'event_store_events_in_streams'
14
- belongs_to :event
14
+ belongs_to :event, primary_key: :event_id
15
15
  end
16
16
  end
@@ -6,33 +6,37 @@ require 'activerecord-import'
6
6
  module RailsEventStoreActiveRecord
7
7
  class EventRepository
8
8
  POSITION_SHIFT = 1
9
- SERIALIZED_GLOBAL_STREAM_NAME = "all".freeze
10
9
 
11
- def initialize
12
- @repo_reader = EventRepositoryReader.new
10
+ def initialize(model_factory: WithDefaultModels.new, serializer:)
11
+ @serializer = serializer
12
+
13
+ @event_klass, @stream_klass = model_factory.call
14
+ @repo_reader = EventRepositoryReader.new(@event_klass, @stream_klass, serializer)
15
+ @index_violation_detector = IndexViolationDetector.new(@event_klass.table_name, @stream_klass.table_name)
13
16
  end
14
17
 
15
- def append_to_stream(events, stream, expected_version)
16
- records, event_ids = [], []
17
- Array(events).each do |event|
18
- records << build_event_hash(event)
19
- event_ids << event.event_id
18
+ def append_to_stream(records, stream, expected_version)
19
+ hashes = []
20
+ event_ids = []
21
+ Array(records).each do |record|
22
+ hashes << import_hash(record, record.serialize(serializer))
23
+ event_ids << record.event_id
20
24
  end
21
- add_to_stream(event_ids, stream, expected_version, true) do
22
- Event.import(records)
25
+ add_to_stream(event_ids, stream, expected_version) do
26
+ @event_klass.import(hashes)
23
27
  end
24
28
  end
25
29
 
26
30
  def link_to_stream(event_ids, stream, expected_version)
27
31
  event_ids = Array(event_ids)
28
- (event_ids - Event.where(id: event_ids).pluck(:id)).each do |id|
32
+ (event_ids - @event_klass.where(event_id: event_ids).pluck(:event_id)).each do |id|
29
33
  raise RubyEventStore::EventNotFound.new(id)
30
34
  end
31
- add_to_stream(event_ids, stream, expected_version, nil)
35
+ add_to_stream(event_ids, stream, expected_version)
32
36
  end
33
37
 
34
38
  def delete_stream(stream)
35
- EventInStream.where(stream: stream.name).delete_all
39
+ @stream_klass.where(stream: stream.name).delete_all
36
40
  end
37
41
 
38
42
  def has_event?(event_id)
@@ -51,49 +55,41 @@ module RailsEventStoreActiveRecord
51
55
  @repo_reader.count(specification)
52
56
  end
53
57
 
54
- def update_messages(messages)
55
- hashes = messages.map(&:to_h)
56
- hashes.each{|h| h[:id] = h.delete(:event_id) }
57
- for_update = messages.map(&:event_id)
58
+ def update_messages(records)
59
+ hashes = Array(records).map{|record| import_hash(record, record.serialize(serializer)) }
60
+ for_update = records.map(&:event_id)
58
61
  start_transaction do
59
- existing = Event.where(id: for_update).pluck(:id)
60
- (for_update - existing).each{|id| raise RubyEventStore::EventNotFound.new(id) }
61
- Event.import(hashes, on_duplicate_key_update: [:data, :metadata, :event_type])
62
+ existing = @event_klass.where(event_id: for_update).pluck(:event_id, :id).to_h
63
+ (for_update - existing.keys).each{|id| raise RubyEventStore::EventNotFound.new(id) }
64
+ hashes.each { |h| h[:id] = existing.fetch(h.fetch(:event_id)) }
65
+ @event_klass.import(hashes, on_duplicate_key_update: [:data, :metadata, :event_type, :valid_at])
62
66
  end
63
67
  end
64
68
 
65
69
  def streams_of(event_id)
66
- EventInStream.where(event_id: event_id)
67
- .where.not(stream: SERIALIZED_GLOBAL_STREAM_NAME)
70
+ @stream_klass.where(event_id: event_id)
68
71
  .pluck(:stream)
69
72
  .map{|name| RubyEventStore::Stream.new(name)}
70
73
  end
71
74
 
72
75
  private
76
+ attr_reader :serializer
73
77
 
74
- def add_to_stream(event_ids, stream, expected_version, include_global)
75
- last_stream_version = ->(stream_) { EventInStream.where(stream: stream_.name).order("position DESC").first.try(:position) }
78
+ def add_to_stream(event_ids, stream, expected_version)
79
+ last_stream_version = ->(stream_) { @stream_klass.where(stream: stream_.name).order("position DESC").first.try(:position) }
76
80
  resolved_version = expected_version.resolve_for(stream, last_stream_version)
77
81
 
78
82
  start_transaction do
79
83
  yield if block_given?
80
- in_stream = event_ids.flat_map.with_index do |event_id, index|
81
- position = compute_position(resolved_version, index)
82
- collection = []
83
- collection.unshift({
84
- stream: SERIALIZED_GLOBAL_STREAM_NAME,
85
- position: nil,
86
- event_id: event_id,
87
- }) if include_global
88
- collection.unshift({
84
+ in_stream = event_ids.map.with_index do |event_id, index|
85
+ {
89
86
  stream: stream.name,
90
- position: position,
91
- event_id: event_id
92
- }) unless stream.global?
93
- collection
87
+ position: compute_position(resolved_version, index),
88
+ event_id: event_id,
89
+ }
94
90
  end
95
91
  fill_ids(in_stream)
96
- EventInStream.import(in_stream)
92
+ @stream_klass.import(in_stream) unless stream.global?
97
93
  end
98
94
  self
99
95
  rescue ActiveRecord::RecordNotUnique => e
@@ -114,24 +110,30 @@ module RailsEventStoreActiveRecord
114
110
  end
115
111
 
116
112
  def detect_index_violated(message)
117
- IndexViolationDetector.new.detect(message)
113
+ @index_violation_detector.detect(message)
118
114
  end
119
115
 
120
- def build_event_hash(serialized_record)
116
+ def import_hash(record, serialized_record)
121
117
  {
122
- id: serialized_record.event_id,
118
+ event_id: serialized_record.event_id,
123
119
  data: serialized_record.data,
124
120
  metadata: serialized_record.metadata,
125
- event_type: serialized_record.event_type
121
+ event_type: serialized_record.event_type,
122
+ created_at: record.timestamp,
123
+ valid_at: optimize_timestamp(record.valid_at, record.timestamp),
126
124
  }
127
125
  end
128
126
 
127
+ def optimize_timestamp(valid_at, created_at)
128
+ valid_at unless valid_at.eql?(created_at)
129
+ end
130
+
129
131
  # Overwritten in a sub-class
130
132
  def fill_ids(_in_stream)
131
133
  end
132
134
 
133
135
  def start_transaction(&block)
134
- ActiveRecord::Base.transaction(requires_new: true, &block)
136
+ @event_klass.transaction(requires_new: true, &block)
135
137
  end
136
138
  end
137
139
 
@@ -3,92 +3,156 @@
3
3
  module RailsEventStoreActiveRecord
4
4
  class EventRepositoryReader
5
5
 
6
+ def initialize(event_klass, stream_klass, serializer)
7
+ @event_klass = event_klass
8
+ @stream_klass = stream_klass
9
+ @serializer = serializer
10
+ end
11
+
6
12
  def has_event?(event_id)
7
- Event.exists?(id: event_id)
13
+ @event_klass.exists?(event_id: event_id)
8
14
  end
9
15
 
10
16
  def last_stream_event(stream)
11
- record = EventInStream.where(stream: stream.name).order('position DESC, id DESC').first
12
- record && build_serialized_record(record)
17
+ record_ = @stream_klass.where(stream: stream.name).order('position DESC, id DESC').first
18
+ record(record_) if record_
13
19
  end
14
20
 
15
21
  def read(spec)
16
- raise RubyEventStore::ReservedInternalName if spec.stream.name.eql?(EventRepository::SERIALIZED_GLOBAL_STREAM_NAME)
17
-
18
22
  stream = read_scope(spec)
19
23
 
20
24
  if spec.batched?
21
25
  batch_reader = ->(offset_id, limit) do
22
- records = offset_id.nil? ? stream.limit(limit) : stream.where(start_offset_condition(spec, offset_id)).limit(limit)
23
- [records.map(&method(:build_serialized_record)), records.last]
26
+ search_in = spec.stream.global? ? @event_klass.table_name : @stream_klass.table_name
27
+ records = offset_id.nil? ? stream.limit(limit) : stream.where(start_offset_condition(spec, offset_id, search_in)).limit(limit)
28
+ [records.map(&method(:record)), records.last]
24
29
  end
25
30
  BatchEnumerator.new(spec.batch_size, spec.limit, batch_reader).each
26
31
  elsif spec.first?
27
- record = stream.first
28
- build_serialized_record(record) if record
32
+ record_ = stream.first
33
+ record(record_) if record_
29
34
  elsif spec.last?
30
- record = stream.last
31
- build_serialized_record(record) if record
35
+ record_ = stream.last
36
+ record(record_) if record_
32
37
  else
33
- stream.map(&method(:build_serialized_record)).each
38
+ stream.map(&method(:record)).each
34
39
  end
35
40
  end
36
41
 
37
42
  def count(spec)
38
- raise RubyEventStore::ReservedInternalName if spec.stream.name.eql?(EventRepository::SERIALIZED_GLOBAL_STREAM_NAME)
39
-
40
43
  read_scope(spec).count
41
44
  end
42
45
 
43
46
  private
47
+ attr_reader :serializer
44
48
 
45
49
  def read_scope(spec)
46
- stream = EventInStream.preload(:event).where(stream: normalize_stream_name(spec))
47
- stream = stream.where(event_id: spec.with_ids) if spec.with_ids?
48
- stream = stream.joins(:event).where(event_store_events: {event_type: spec.with_types}) if spec.with_types?
49
- stream = stream.order(position: order(spec)) unless spec.stream.global?
50
- stream = stream.limit(spec.limit) if spec.limit?
51
- stream = stream.where(start_condition(spec)) if spec.start
52
- stream = stream.where(stop_condition(spec)) if spec.stop
53
- stream = stream.order(id: order(spec))
54
- stream
50
+ if spec.stream.global?
51
+ stream = @event_klass
52
+ stream = stream.where(event_id: spec.with_ids) if spec.with_ids?
53
+ stream = stream.where(event_type: spec.with_types) if spec.with_types?
54
+ stream = ordered(stream, spec)
55
+ stream = stream.limit(spec.limit) if spec.limit?
56
+ stream = stream.where(start_condition_in_global_stream(spec)) if spec.start
57
+ stream = stream.where(stop_condition_in_global_stream(spec)) if spec.stop
58
+ stream = stream.where(older_than_condition(spec)) if spec.older_than
59
+ stream = stream.where(older_than_or_equal_condition(spec)) if spec.older_than_or_equal
60
+ stream = stream.where(newer_than_condition(spec)) if spec.newer_than
61
+ stream = stream.where(newer_than_or_equal_condition(spec)) if spec.newer_than_or_equal
62
+ stream.order(id: order(spec))
63
+ else
64
+ stream = @stream_klass.preload(:event).where(stream: spec.stream.name)
65
+ stream = stream.where(event_id: spec.with_ids) if spec.with_ids?
66
+ stream = stream.where(@event_klass.table_name => {event_type: spec.with_types}) if spec.with_types?
67
+ stream = ordered(stream.joins(:event), spec)
68
+ stream = stream.order(position: order(spec), id: order(spec))
69
+ stream = stream.limit(spec.limit) if spec.limit?
70
+ stream = stream.where(start_condition(spec)) if spec.start
71
+ stream = stream.where(stop_condition(spec)) if spec.stop
72
+ stream = stream.where(older_than_condition(spec)) if spec.older_than
73
+ stream = stream.where(older_than_or_equal_condition(spec)) if spec.older_than_or_equal
74
+ stream = stream.where(newer_than_condition(spec)) if spec.newer_than
75
+ stream = stream.where(newer_than_or_equal_condition(spec)) if spec.newer_than_or_equal
76
+ stream
77
+ end
55
78
  end
56
79
 
57
- def normalize_stream_name(specification)
58
- specification.stream.global? ? EventRepository::SERIALIZED_GLOBAL_STREAM_NAME : specification.stream.name
80
+ def ordered(stream, spec)
81
+ case spec.time_sort_by
82
+ when :as_at
83
+ stream.order("#{@event_klass.table_name}.created_at #{order(spec)}")
84
+ when :as_of
85
+ stream.order("#{@event_klass.table_name}.valid_at #{order(spec)}")
86
+ else
87
+ stream
88
+ end
59
89
  end
60
90
 
61
- def start_offset_condition(specification, record_id)
62
- condition = specification.forward? ? 'event_store_events_in_streams.id > ?' : 'event_store_events_in_streams.id < ?'
91
+ def start_offset_condition(specification, record_id, search_in)
92
+ condition = "#{search_in}.id #{specification.forward? ? '>' : '<'} ?"
63
93
  [condition, record_id]
64
94
  end
65
95
 
66
- def stop_offset_condition(specification, record_id)
67
- condition = specification.forward? ? 'event_store_events_in_streams.id < ?' : 'event_store_events_in_streams.id > ?'
96
+ def stop_offset_condition(specification, record_id, search_in)
97
+ condition = "#{search_in}.id #{specification.forward? ? '<' : '>'} ?"
68
98
  [condition, record_id]
69
99
  end
70
100
 
71
101
  def start_condition(specification)
72
102
  start_offset_condition(specification,
73
- EventInStream.find_by!(event_id: specification.start, stream: normalize_stream_name(specification)))
103
+ @stream_klass.find_by!(event_id: specification.start, stream: specification.stream.name),
104
+ @stream_klass.table_name)
74
105
  end
75
106
 
76
107
  def stop_condition(specification)
77
108
  stop_offset_condition(specification,
78
- EventInStream.find_by!(event_id: specification.stop, stream: normalize_stream_name(specification)))
109
+ @stream_klass.find_by!(event_id: specification.stop, stream: specification.stream.name),
110
+ @stream_klass.table_name)
111
+ end
112
+
113
+ def start_condition_in_global_stream(specification)
114
+ start_offset_condition(specification,
115
+ @event_klass.find_by!(event_id: specification.start),
116
+ @event_klass.table_name)
117
+ end
118
+
119
+ def stop_condition_in_global_stream(specification)
120
+ stop_offset_condition(specification,
121
+ @event_klass.find_by!(event_id: specification.stop),
122
+ @event_klass.table_name)
123
+ end
124
+
125
+ def older_than_condition(specification)
126
+ ["#{@event_klass.table_name}.created_at < ?", specification.older_than]
127
+ end
128
+
129
+ def older_than_or_equal_condition(specification)
130
+ ["#{@event_klass.table_name}.created_at <= ?", specification.older_than_or_equal]
131
+ end
132
+
133
+ def newer_than_condition(specification)
134
+ ["#{@event_klass.table_name}.created_at > ?", specification.newer_than]
135
+ end
136
+
137
+ def newer_than_or_equal_condition(specification)
138
+ ["#{@event_klass.table_name}.created_at >= ?", specification.newer_than_or_equal]
79
139
  end
80
140
 
81
141
  def order(spec)
82
142
  spec.forward? ? 'ASC' : 'DESC'
83
143
  end
84
144
 
85
- def build_serialized_record(record)
145
+ def record(record)
146
+ record = record.event if @stream_klass === record
147
+
86
148
  RubyEventStore::SerializedRecord.new(
87
- event_id: record.event.id,
88
- metadata: record.event.metadata,
89
- data: record.event.data,
90
- event_type: record.event.event_type
91
- )
149
+ event_id: record.event_id,
150
+ metadata: record.metadata,
151
+ data: record.data,
152
+ event_type: record.event_type,
153
+ timestamp: record.created_at.iso8601(RubyEventStore::TIMESTAMP_PRECISION),
154
+ valid_at: (record.valid_at || record.created_at).iso8601(RubyEventStore::TIMESTAMP_PRECISION),
155
+ ).deserialize(serializer)
92
156
  end
93
157
  end
94
158
 
@@ -6,11 +6,11 @@ rescue LoadError
6
6
  end
7
7
 
8
8
  module RailsEventStoreActiveRecord
9
- class LimitForEventIdGenerator < Rails::Generators::Base
9
+ class AddValidAtGenerator < Rails::Generators::Base
10
10
  source_root File.expand_path(File.join(File.dirname(__FILE__), '../generators/templates'))
11
11
 
12
12
  def create_migration
13
- template "limit_for_event_id_template.rb", "db/migrate/#{timestamp}_limit_for_event_id.rb"
13
+ template "add_valid_at_template.rb", "db/migrate/#{timestamp}_add_valid_at.rb"
14
14
  end
15
15
 
16
16
  private
@@ -6,11 +6,11 @@ rescue LoadError
6
6
  end
7
7
 
8
8
  module RailsEventStoreActiveRecord
9
- class IndexByEventTypeGenerator < Rails::Generators::Base
9
+ class CreatedAtPrecisionGenerator < Rails::Generators::Base
10
10
  source_root File.expand_path(File.join(File.dirname(__FILE__), '../generators/templates'))
11
11
 
12
12
  def create_migration
13
- template "index_by_event_type_template.rb", "db/migrate/#{timestamp}_index_by_event_type.rb"
13
+ template "created_at_precision_template.rb", "db/migrate/#{timestamp}_created_at_precision.rb"
14
14
  end
15
15
 
16
16
  private
@@ -1,16 +1,14 @@
1
- # frozen_string_literal: true
2
-
3
1
  begin
4
2
  require 'rails/generators'
5
3
  rescue LoadError
6
4
  end
7
5
 
8
6
  module RailsEventStoreActiveRecord
9
- class BinaryDataAndMetadataGenerator < Rails::Generators::Base
7
+ class NoGlobalStreamEntriesGenerator < Rails::Generators::Base
10
8
  source_root File.expand_path(File.join(File.dirname(__FILE__), '../generators/templates'))
11
9
 
12
10
  def create_migration
13
- template "binary_data_and_metadata_template.rb", "db/migrate/#{timestamp}_binary_data_and_metadata.rb"
11
+ template "no_global_stream_entries_template.rb", "db/migrate/#{timestamp}_no_global_stream_entries.rb"
14
12
  end
15
13
 
16
14
  private
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddValidAt < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ case ActiveRecord::Base.connection.adapter_name
6
+ when "PostgreSQL"
7
+ add_column :event_store_events, :valid_at, :datetime, null: true
8
+ else
9
+ add_column :event_store_events, :valid_at, :datetime, precision: 6, null: true
10
+ end
11
+
12
+ add_index :event_store_events, :valid_at
13
+ end
14
+ end
@@ -4,7 +4,7 @@ class CreateEventStoreEvents < ActiveRecord::Migration<%= migration_version %>
4
4
  def change
5
5
  postgres = ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
6
6
  sqlite = ActiveRecord::Base.connection.adapter_name == "SQLite"
7
- rails_42 = Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new("5.0.0")
7
+
8
8
  enable_extension "pgcrypto" if postgres
9
9
  create_table(:event_store_events_in_streams, force: false) do |t|
10
10
  t.string :stream, null: false
@@ -14,32 +14,38 @@ class CreateEventStoreEvents < ActiveRecord::Migration<%= migration_version %>
14
14
  else
15
15
  t.references :event, null: false, type: :string, limit: 36
16
16
  end
17
- t.datetime :created_at, null: false
17
+ if postgres
18
+ t.datetime :created_at, null: false
19
+ else
20
+ t.datetime :created_at, null: false, precision: 6
21
+ end
18
22
  end
19
23
  add_index :event_store_events_in_streams, [:stream, :position], unique: true
20
24
  add_index :event_store_events_in_streams, [:created_at]
21
25
  add_index :event_store_events_in_streams, [:stream, :event_id], unique: true
22
26
 
23
27
  if postgres
24
- create_table(:event_store_events, id: :uuid, default: 'gen_random_uuid()', force: false) do |t|
28
+ create_table(:event_store_events, force: false) do |t|
29
+ t.references :event, null: false, type: :uuid
25
30
  t.string :event_type, null: false
26
31
  t.<%= data_type %> :metadata
27
32
  t.<%= data_type %> :data, null: false
28
33
  t.datetime :created_at, null: false
34
+ t.datetime :valid_at, null: true
29
35
  end
30
36
  else
31
- create_table(:event_store_events, id: false, force: false) do |t|
32
- t.string :id, limit: 36, primary_key: true, null: false
37
+ create_table(:event_store_events, force: false) do |t|
38
+ t.references :event, null: false, type: :string, limit: 36
33
39
  t.string :event_type, null: false
34
40
  t.binary :metadata
35
41
  t.binary :data, null: false
36
- t.datetime :created_at, null: false
37
- end
38
- if sqlite && rails_42
39
- add_index :event_store_events, :id, unique: true
42
+ t.datetime :created_at, null: false, precision: 6
43
+ t.datetime :valid_at, null: true, precision: 6
40
44
  end
41
45
  end
46
+ add_index :event_store_events, :event_id, unique: true
42
47
  add_index :event_store_events, :created_at
48
+ add_index :event_store_events, :valid_at
43
49
  add_index :event_store_events, :event_type
44
50
  end
45
51
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreatedAtPrecision < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ case ActiveRecord::Base.connection.adapter_name
6
+ when "SQLite"
7
+ rename_table :event_store_events, :old_event_store_events
8
+ create_table(:event_store_events, id: false, force: false) do |t|
9
+ t.string :id, limit: 36, primary_key: true, null: false
10
+ t.string :event_type, null: false
11
+ t.binary :metadata
12
+ t.binary :data, null: false
13
+ t.datetime :created_at, null: false, precision: 6
14
+ end
15
+ add_index :event_store_events, :created_at
16
+ add_index :event_store_events, :event_type
17
+ execute <<-SQL
18
+ INSERT INTO event_store_events(id, event_type, metadata, data, created_at)
19
+ SELECT id, event_type, metadata, data, created_at FROM old_event_store_events;
20
+ SQL
21
+ drop_table :old_event_store_events
22
+
23
+ rename_table :event_store_events_in_streams, :old_event_store_events_in_streams
24
+ create_table(:event_store_events_in_streams, force: false) do |t|
25
+ t.string :stream, null: false
26
+ t.integer :position, null: true
27
+ t.references :event, null: false, type: :string, limit: 36
28
+ t.datetime :created_at, null: false, precision: 6
29
+ end
30
+ add_index :event_store_events_in_streams, [:stream, :position], unique: true
31
+ add_index :event_store_events_in_streams, [:created_at]
32
+ add_index :event_store_events_in_streams, [:stream, :event_id], unique: true
33
+
34
+ execute <<-SQL
35
+ INSERT INTO event_store_events_in_streams(id, stream, position, event_id, created_at)
36
+ SELECT id, stream, position, event_id, created_at FROM old_event_store_events_in_streams;
37
+ SQL
38
+ drop_table :old_event_store_events_in_streams
39
+ when "PostgreSQL"
40
+ else
41
+ change_column :event_store_events, :created_at, :datetime, precision: 6
42
+ change_column :event_store_events_in_streams, :created_at, :datetime, precision: 6
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,59 @@
1
+ class NoGlobalStreamEntries < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ case ActiveRecord::Base.connection.adapter_name
4
+ when "SQLite"
5
+ rename_table :event_store_events, :old_event_store_events
6
+ create_table(:event_store_events, force: false) do |t|
7
+ t.references :event, null: false, type: :string, limit: 36
8
+ t.string :event_type, null: false
9
+ t.binary :metadata
10
+ t.binary :data, null: false
11
+ t.datetime :created_at, precision: 6, null: false
12
+ t.datetime :valid_at, precision: 6, null: true
13
+ end
14
+ add_index :event_store_events, :event_id, unique: true
15
+ add_index :event_store_events, :created_at
16
+ add_index :event_store_events, :valid_at
17
+ add_index :event_store_events, :event_type
18
+
19
+ execute <<-SQL
20
+ INSERT INTO event_store_events(event_id, event_type, metadata, data, created_at)
21
+ SELECT id, event_type, metadata, data, created_at FROM old_event_store_events;
22
+ SQL
23
+ drop_table :old_event_store_events
24
+ when "PostgreSQL"
25
+ rename_column :event_store_events, :id, :event_id
26
+ change_column_default :event_store_events, :event_id, nil
27
+ add_column :event_store_events, :id, :serial
28
+
29
+ execute <<~SQL
30
+ UPDATE event_store_events
31
+ SET id = event_store_events_in_streams.id
32
+ FROM event_store_events_in_streams
33
+ WHERE event_store_events.event_id = event_store_events_in_streams.event_id AND event_store_events_in_streams.stream = 'all';
34
+ UPDATE event_store_events
35
+ SET id = ese.new_id
36
+ FROM (SELECT id, row_number() OVER (ORDER BY id) AS new_id FROM event_store_events) ese
37
+ WHERE event_store_events.id = ese.id;
38
+ SELECT setval(pg_get_serial_sequence('event_store_events', 'id'), max(id)) FROM event_store_events;
39
+ ALTER TABLE event_store_events DROP CONSTRAINT event_store_events_pkey;
40
+ ALTER TABLE event_store_events ADD PRIMARY KEY (id);
41
+ SQL
42
+ add_index :event_store_events, :event_id, unique: true
43
+ else
44
+ rename_column :event_store_events, :id, :event_id
45
+ add_column :event_store_events, :id, :integer
46
+
47
+ execute <<-SQL
48
+ UPDATE event_store_events
49
+ INNER JOIN event_store_events_in_streams ON (event_store_events.event_id = event_store_events_in_streams.event_id)
50
+ SET event_store_events.id = event_store_events_in_streams.id
51
+ WHERE event_store_events_in_streams.stream = 'all';
52
+ SQL
53
+ execute "SET @row_number = 0"
54
+ execute "UPDATE event_store_events SET event_store_events.id = (@row_number:=@row_number + 1) ORDER BY id"
55
+ execute "ALTER TABLE event_store_events DROP PRIMARY KEY, ADD PRIMARY KEY (id), MODIFY id INT AUTO_INCREMENT"
56
+ add_index :event_store_events, :event_id, unique: true
57
+ end
58
+ end
59
+ end