rails_event_store_active_record 1.3.0 → 2.2.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 (25) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -2
  3. data/lib/rails_event_store_active_record.rb +10 -11
  4. data/lib/rails_event_store_active_record/event.rb +1 -1
  5. data/lib/rails_event_store_active_record/event_repository.rb +44 -48
  6. data/lib/rails_event_store_active_record/event_repository_reader.rb +118 -41
  7. data/lib/rails_event_store_active_record/generators/migration_generator.rb +1 -6
  8. data/lib/rails_event_store_active_record/generators/templates/create_event_store_events_template.rb +15 -10
  9. data/lib/rails_event_store_active_record/index_violation_detector.rb +33 -18
  10. data/lib/rails_event_store_active_record/version.rb +1 -1
  11. data/lib/rails_event_store_active_record/with_abstract_base_class.rb +39 -0
  12. data/lib/rails_event_store_active_record/with_default_models.rb +9 -0
  13. metadata +22 -42
  14. data/CHANGELOG.md +0 -75
  15. data/Gemfile +0 -18
  16. data/Makefile +0 -28
  17. data/bin/console +0 -14
  18. data/bin/setup +0 -7
  19. data/lib/rails_event_store_active_record/generators/binary_data_and_metadata_generator.rb +0 -31
  20. data/lib/rails_event_store_active_record/generators/index_by_event_type_generator.rb +0 -31
  21. data/lib/rails_event_store_active_record/generators/limit_for_event_id_generator.rb +0 -31
  22. data/lib/rails_event_store_active_record/generators/templates/binary_data_and_metadata_template.rb +0 -35
  23. data/lib/rails_event_store_active_record/generators/templates/index_by_event_type_template.rb +0 -7
  24. data/lib/rails_event_store_active_record/generators/templates/limit_for_event_id_template.rb +0 -8
  25. data/rails_event_store_active_record.gemspec +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0deda45046d7c0914a105aa67fe9c694550a7a3c07aec439a80a5b01a2a13418
4
- data.tar.gz: 664c1aa606c495b81081861adca51af9d9829f40cdafaba61b9b73be586fa867
3
+ metadata.gz: c0bef98dccdd36a255c20ef3bd059921c483fe3e9e448bd53c48fa23c6032692
4
+ data.tar.gz: 02f25563e5d185d4d19fbe79e92d83d2c8abe14281797f2d365db970664f464e
5
5
  SHA512:
6
- metadata.gz: ef624e7e400a25baa7a6b8a444c585a0d568673914f15d51a22a910f1152e2239585df0bf8cfe0ecd958b768bb14d2c7813035f5cd80263aebcbfdb307909440
7
- data.tar.gz: 218e460ff03c3efbb924a9a0911a7e82e38d2c7684d430c8b8791d674bdfa1f1a61953386f1008a3a728d5b9918f1de21aacf5d831429bb54328ea93c372d45f
6
+ metadata.gz: 3949e5687ec1647b7257c25cf337f488f012df089226819e4b4198937b72eb8d3d1c1e8d09fbb4cf46711abf583743c49edfd76c00def3f1f5800b555db0fa1e
7
+ data.tar.gz: 5dd00bbb2a01217095c8e5ed4130582e0f8a23b6cb0fdaf6cb8c94f70afe371648197b3f5cbf8a98e0711e529b3ae87c02619a1372be3679f808ee2367e49f26
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # RailsEventStoreActiveRecord
2
2
 
3
- An Active Record based implementation of events repository for [Rails Event Store](https://github.com/RailsEventStore/rails_event_store).
3
+ Persistent event repository implementation for RubyEventStore based on ActiveRecord. Ships with database schema and migrations suitable for PostgreSQL, MySQL ans SQLite database engines.
4
4
 
5
- This is the default repository used in `rails_event_store` gem.
5
+ Includes repository implementation with linearized writes to achieve log-like properties of streams on top of SQL database engine.
6
+
7
+ Find out more at [https://railseventstore.org](https://railseventstore.org/)
@@ -1,13 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails_event_store_active_record/generators/migration_generator'
4
- require 'rails_event_store_active_record/generators/index_by_event_type_generator'
5
- require 'rails_event_store_active_record/generators/limit_for_event_id_generator'
6
- require 'rails_event_store_active_record/generators/binary_data_and_metadata_generator'
7
- require 'rails_event_store_active_record/event'
8
- require 'rails_event_store_active_record/event_repository'
9
- require 'rails_event_store_active_record/batch_enumerator'
10
- require 'rails_event_store_active_record/event_repository_reader'
11
- require 'rails_event_store_active_record/index_violation_detector'
12
- require 'rails_event_store_active_record/pg_linearized_event_repository'
13
- require 'rails_event_store_active_record/version'
3
+ require_relative 'rails_event_store_active_record/generators/migration_generator'
4
+ require_relative 'rails_event_store_active_record/event'
5
+ require_relative 'rails_event_store_active_record/with_default_models'
6
+ require_relative 'rails_event_store_active_record/with_abstract_base_class'
7
+ require_relative 'rails_event_store_active_record/event_repository'
8
+ require_relative 'rails_event_store_active_record/batch_enumerator'
9
+ require_relative 'rails_event_store_active_record/event_repository_reader'
10
+ require_relative 'rails_event_store_active_record/index_violation_detector'
11
+ require_relative 'rails_event_store_active_record/pg_linearized_event_repository'
12
+ require_relative 'rails_event_store_active_record/version'
@@ -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,36 @@ 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
+ 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
- event_ids = Array(event_ids)
28
- (event_ids - Event.where(id: event_ids).pluck(:id)).each do |id|
31
+ (event_ids - @event_klass.where(event_id: event_ids).pluck(:event_id)).each do |id|
29
32
  raise RubyEventStore::EventNotFound.new(id)
30
33
  end
31
- add_to_stream(event_ids, stream, expected_version, nil)
34
+ add_to_stream(event_ids, stream, expected_version)
32
35
  end
33
36
 
34
37
  def delete_stream(stream)
35
- EventInStream.where(stream: stream.name).delete_all
38
+ @stream_klass.where(stream: stream.name).delete_all
36
39
  end
37
40
 
38
41
  def has_event?(event_id)
@@ -51,49 +54,40 @@ module RailsEventStoreActiveRecord
51
54
  @repo_reader.count(specification)
52
55
  end
53
56
 
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)
57
+ def update_messages(records)
58
+ hashes = records.map { |record| import_hash(record, record.serialize(serializer)) }
59
+ for_update = records.map(&:event_id)
58
60
  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])
61
+ existing = @event_klass.where(event_id: for_update).pluck(:event_id, :id).to_h
62
+ (for_update - existing.keys).each{|id| raise RubyEventStore::EventNotFound.new(id) }
63
+ hashes.each { |h| h[:id] = existing.fetch(h.fetch(:event_id)) }
64
+ @event_klass.import(hashes, on_duplicate_key_update: [:data, :metadata, :event_type, :valid_at])
62
65
  end
63
66
  end
64
67
 
65
68
  def streams_of(event_id)
66
- EventInStream.where(event_id: event_id)
67
- .where.not(stream: SERIALIZED_GLOBAL_STREAM_NAME)
69
+ @stream_klass.where(event_id: event_id)
68
70
  .pluck(:stream)
69
- .map{|name| RubyEventStore::Stream.new(name)}
71
+ .map { |name| RubyEventStore::Stream.new(name) }
70
72
  end
71
73
 
72
74
  private
75
+ attr_reader :serializer
73
76
 
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) }
77
+ def add_to_stream(event_ids, stream, expected_version)
78
+ last_stream_version = ->(stream_) { @stream_klass.where(stream: stream_.name).order("position DESC").first.try(:position) }
76
79
  resolved_version = expected_version.resolve_for(stream, last_stream_version)
77
80
 
78
81
  start_transaction do
79
82
  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({
83
+ in_stream = event_ids.map.with_index do |event_id, index|
84
+ {
89
85
  stream: stream.name,
90
- position: position,
91
- event_id: event_id
92
- }) unless stream.global?
93
- collection
86
+ position: compute_position(resolved_version, index),
87
+ event_id: event_id,
88
+ }
94
89
  end
95
- fill_ids(in_stream)
96
- EventInStream.import(in_stream)
90
+ @stream_klass.import(in_stream) unless stream.global?
97
91
  end
98
92
  self
99
93
  rescue ActiveRecord::RecordNotUnique => e
@@ -114,24 +108,26 @@ module RailsEventStoreActiveRecord
114
108
  end
115
109
 
116
110
  def detect_index_violated(message)
117
- IndexViolationDetector.new.detect(message)
111
+ @index_violation_detector.detect(message)
118
112
  end
119
113
 
120
- def build_event_hash(serialized_record)
114
+ def import_hash(record, serialized_record)
121
115
  {
122
- id: serialized_record.event_id,
116
+ event_id: serialized_record.event_id,
123
117
  data: serialized_record.data,
124
118
  metadata: serialized_record.metadata,
125
- event_type: serialized_record.event_type
119
+ event_type: serialized_record.event_type,
120
+ created_at: record.timestamp,
121
+ valid_at: optimize_timestamp(record.valid_at, record.timestamp),
126
122
  }
127
123
  end
128
124
 
129
- # Overwritten in a sub-class
130
- def fill_ids(_in_stream)
125
+ def optimize_timestamp(valid_at, created_at)
126
+ valid_at unless valid_at.eql?(created_at)
131
127
  end
132
128
 
133
129
  def start_transaction(&block)
134
- ActiveRecord::Base.transaction(requires_new: true, &block)
130
+ @event_klass.transaction(requires_new: true, &block)
135
131
  end
136
132
  end
137
133
 
@@ -3,92 +3,169 @@
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
-
20
23
  if spec.batched?
21
- 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]
24
- end
25
- BatchEnumerator.new(spec.batch_size, spec.limit, batch_reader).each
24
+ spec.time_sort_by ? offset_limit_batch_reader(spec, stream) : monotonic_id_batch_reader(spec, stream)
26
25
  elsif spec.first?
27
- record = stream.first
28
- build_serialized_record(record) if record
26
+ record_ = stream.first
27
+ record(record_) if record_
29
28
  elsif spec.last?
30
- record = stream.last
31
- build_serialized_record(record) if record
29
+ record_ = stream.last
30
+ record(record_) if record_
32
31
  else
33
- stream.map(&method(:build_serialized_record)).each
32
+ stream.map(&method(:record)).each
34
33
  end
35
34
  end
36
35
 
37
36
  def count(spec)
38
- raise RubyEventStore::ReservedInternalName if spec.stream.name.eql?(EventRepository::SERIALIZED_GLOBAL_STREAM_NAME)
39
-
40
37
  read_scope(spec).count
41
38
  end
42
39
 
43
40
  private
41
+ attr_reader :serializer
42
+
43
+ def offset_limit_batch_reader(spec, stream)
44
+ batch_reader = ->(offset, limit) do
45
+ stream
46
+ .offset(offset)
47
+ .limit(limit)
48
+ .map(&method(:record))
49
+ end
50
+ RubyEventStore::BatchEnumerator.new(spec.batch_size, spec.limit, batch_reader).each
51
+ end
52
+
53
+ def monotonic_id_batch_reader(spec, stream)
54
+ batch_reader = ->(offset_id, limit) do
55
+ search_in = spec.stream.global? ? @event_klass.table_name : @stream_klass.table_name
56
+ records = offset_id.nil? ? stream.limit(limit) : stream.where(start_offset_condition(spec, offset_id, search_in)).limit(limit)
57
+ [records.map(&method(:record)), records.last]
58
+ end
59
+ BatchEnumerator.new(spec.batch_size, spec.limit, batch_reader).each
60
+ end
44
61
 
45
62
  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
63
+ if spec.stream.global?
64
+ stream = @event_klass
65
+ stream = stream.where(event_id: spec.with_ids) if spec.with_ids?
66
+ stream = stream.where(event_type: spec.with_types) if spec.with_types?
67
+ stream = ordered(stream, spec)
68
+ stream = stream.limit(spec.limit) if spec.limit?
69
+ stream = stream.where(start_condition_in_global_stream(spec)) if spec.start
70
+ stream = stream.where(stop_condition_in_global_stream(spec)) if spec.stop
71
+ stream = stream.where(older_than_condition(spec)) if spec.older_than
72
+ stream = stream.where(older_than_or_equal_condition(spec)) if spec.older_than_or_equal
73
+ stream = stream.where(newer_than_condition(spec)) if spec.newer_than
74
+ stream = stream.where(newer_than_or_equal_condition(spec)) if spec.newer_than_or_equal
75
+ stream.order(id: order(spec))
76
+ else
77
+ stream = @stream_klass.preload(:event).where(stream: spec.stream.name)
78
+ stream = stream.where(event_id: spec.with_ids) if spec.with_ids?
79
+ stream = stream.where(@event_klass.table_name => {event_type: spec.with_types}) if spec.with_types?
80
+ stream = ordered(stream.joins(:event), spec)
81
+ stream = stream.order(position: order(spec), id: order(spec))
82
+ stream = stream.limit(spec.limit) if spec.limit?
83
+ stream = stream.where(start_condition(spec)) if spec.start
84
+ stream = stream.where(stop_condition(spec)) if spec.stop
85
+ stream = stream.where(older_than_condition(spec)) if spec.older_than
86
+ stream = stream.where(older_than_or_equal_condition(spec)) if spec.older_than_or_equal
87
+ stream = stream.where(newer_than_condition(spec)) if spec.newer_than
88
+ stream = stream.where(newer_than_or_equal_condition(spec)) if spec.newer_than_or_equal
89
+ stream
90
+ end
55
91
  end
56
92
 
57
- def normalize_stream_name(specification)
58
- specification.stream.global? ? EventRepository::SERIALIZED_GLOBAL_STREAM_NAME : specification.stream.name
93
+ def ordered(stream, spec)
94
+ case spec.time_sort_by
95
+ when :as_at
96
+ stream.order("#{@event_klass.table_name}.created_at #{order(spec)}")
97
+ when :as_of
98
+ stream.order("#{@event_klass.table_name}.valid_at #{order(spec)}")
99
+ else
100
+ stream
101
+ end
59
102
  end
60
103
 
61
- def start_offset_condition(specification, record_id)
62
- condition = specification.forward? ? 'event_store_events_in_streams.id > ?' : 'event_store_events_in_streams.id < ?'
104
+ def start_offset_condition(specification, record_id, search_in)
105
+ condition = "#{search_in}.id #{specification.forward? ? '>' : '<'} ?"
63
106
  [condition, record_id]
64
107
  end
65
108
 
66
- def stop_offset_condition(specification, record_id)
67
- condition = specification.forward? ? 'event_store_events_in_streams.id < ?' : 'event_store_events_in_streams.id > ?'
109
+ def stop_offset_condition(specification, record_id, search_in)
110
+ condition = "#{search_in}.id #{specification.forward? ? '<' : '>'} ?"
68
111
  [condition, record_id]
69
112
  end
70
113
 
71
114
  def start_condition(specification)
72
115
  start_offset_condition(specification,
73
- EventInStream.find_by!(event_id: specification.start, stream: normalize_stream_name(specification)))
116
+ @stream_klass.find_by!(event_id: specification.start, stream: specification.stream.name),
117
+ @stream_klass.table_name)
74
118
  end
75
119
 
76
120
  def stop_condition(specification)
77
121
  stop_offset_condition(specification,
78
- EventInStream.find_by!(event_id: specification.stop, stream: normalize_stream_name(specification)))
122
+ @stream_klass.find_by!(event_id: specification.stop, stream: specification.stream.name),
123
+ @stream_klass.table_name)
124
+ end
125
+
126
+ def start_condition_in_global_stream(specification)
127
+ start_offset_condition(specification,
128
+ @event_klass.find_by!(event_id: specification.start),
129
+ @event_klass.table_name)
130
+ end
131
+
132
+ def stop_condition_in_global_stream(specification)
133
+ stop_offset_condition(specification,
134
+ @event_klass.find_by!(event_id: specification.stop),
135
+ @event_klass.table_name)
136
+ end
137
+
138
+ def older_than_condition(specification)
139
+ ["#{@event_klass.table_name}.created_at < ?", specification.older_than]
140
+ end
141
+
142
+ def older_than_or_equal_condition(specification)
143
+ ["#{@event_klass.table_name}.created_at <= ?", specification.older_than_or_equal]
144
+ end
145
+
146
+ def newer_than_condition(specification)
147
+ ["#{@event_klass.table_name}.created_at > ?", specification.newer_than]
148
+ end
149
+
150
+ def newer_than_or_equal_condition(specification)
151
+ ["#{@event_klass.table_name}.created_at >= ?", specification.newer_than_or_equal]
79
152
  end
80
153
 
81
154
  def order(spec)
82
155
  spec.forward? ? 'ASC' : 'DESC'
83
156
  end
84
157
 
85
- def build_serialized_record(record)
158
+ def record(record)
159
+ record = record.event if @stream_klass === record
160
+
86
161
  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
- )
162
+ event_id: record.event_id,
163
+ metadata: record.metadata,
164
+ data: record.data,
165
+ event_type: record.event_type,
166
+ timestamp: record.created_at.iso8601(RubyEventStore::TIMESTAMP_PRECISION),
167
+ valid_at: (record.valid_at || record.created_at).iso8601(RubyEventStore::TIMESTAMP_PRECISION),
168
+ ).deserialize(serializer)
92
169
  end
93
170
  end
94
171
 
@@ -16,7 +16,7 @@ module RailsEventStoreActiveRecord
16
16
  :data_type,
17
17
  type: :string,
18
18
  default: 'binary',
19
- desc: "Configure the data type for `data` and `meta data` feilds in Postgres migration (options: #{DATA_TYPES.join('/')})"
19
+ desc: "Configure the data type for `data` and `meta data` fields in Postgres migration (options: #{DATA_TYPES.join('/')})"
20
20
  )
21
21
 
22
22
  def initialize(*args)
@@ -37,12 +37,7 @@ module RailsEventStoreActiveRecord
37
37
  options.fetch('data_type')
38
38
  end
39
39
 
40
- def rails_version
41
- Rails::VERSION::STRING
42
- end
43
-
44
40
  def migration_version
45
- return nil if Gem::Version.new(rails_version) < Gem::Version.new("5.0.0")
46
41
  "[4.2]"
47
42
  end
48
43
 
@@ -4,8 +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")
8
- enable_extension "pgcrypto" if postgres
7
+
9
8
  create_table(:event_store_events_in_streams, force: false) do |t|
10
9
  t.string :stream, null: false
11
10
  t.integer :position, null: true
@@ -14,32 +13,38 @@ class CreateEventStoreEvents < ActiveRecord::Migration<%= migration_version %>
14
13
  else
15
14
  t.references :event, null: false, type: :string, limit: 36
16
15
  end
17
- t.datetime :created_at, null: false
16
+ if postgres
17
+ t.datetime :created_at, null: false
18
+ else
19
+ t.datetime :created_at, null: false, precision: 6
20
+ end
18
21
  end
19
22
  add_index :event_store_events_in_streams, [:stream, :position], unique: true
20
23
  add_index :event_store_events_in_streams, [:created_at]
21
24
  add_index :event_store_events_in_streams, [:stream, :event_id], unique: true
22
25
 
23
26
  if postgres
24
- create_table(:event_store_events, id: :uuid, default: 'gen_random_uuid()', force: false) do |t|
27
+ create_table(:event_store_events, force: false) do |t|
28
+ t.references :event, null: false, type: :uuid
25
29
  t.string :event_type, null: false
26
30
  t.<%= data_type %> :metadata
27
31
  t.<%= data_type %> :data, null: false
28
32
  t.datetime :created_at, null: false
33
+ t.datetime :valid_at, null: true
29
34
  end
30
35
  else
31
- create_table(:event_store_events, id: false, force: false) do |t|
32
- t.string :id, limit: 36, primary_key: true, null: false
36
+ create_table(:event_store_events, force: false) do |t|
37
+ t.references :event, null: false, type: :string, limit: 36
33
38
  t.string :event_type, null: false
34
39
  t.binary :metadata
35
40
  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
41
+ t.datetime :created_at, null: false, precision: 6
42
+ t.datetime :valid_at, null: true, precision: 6
40
43
  end
41
44
  end
45
+ add_index :event_store_events, :event_id, unique: true
42
46
  add_index :event_store_events, :created_at
47
+ add_index :event_store_events, :valid_at
43
48
  add_index :event_store_events, :event_type
44
49
  end
45
50
  end
@@ -2,28 +2,43 @@
2
2
 
3
3
  module RailsEventStoreActiveRecord
4
4
  class IndexViolationDetector
5
- MYSQL5_PKEY_ERROR = "for key 'PRIMARY'".freeze
6
- MYSQL8_PKEY_ERROR = "for key 'event_store_events.PRIMARY'".freeze
7
- POSTGRES_PKEY_ERROR = 'event_store_events_pkey'.freeze
8
- SQLITE3_PKEY_ERROR = 'event_store_events.id'.freeze
9
5
 
10
- MYSQL5_INDEX_ERROR = "for key 'index_event_store_events_in_streams_on_stream_and_event_id'".freeze
11
- MYSQL8_INDEX_ERROR = "for key 'event_store_events_in_streams.index_event_store_events_in_streams_on_stream_and_event_id'".freeze
12
- POSTGRES_INDEX_ERROR = 'Key (stream, event_id)'.freeze
13
- SQLITE3_INDEX_ERROR = 'event_store_events_in_streams.stream, event_store_events_in_streams.event_id'.freeze
6
+ def initialize(event_store_events, event_store_events_in_streams)
7
+ @postgres_pkey_error = "Key (event_id)".freeze
8
+ @postgres_index_error = "Key (stream, event_id)".freeze
9
+ @mysql5_pkey_error = "for key 'index_#{event_store_events}_on_event_id'".freeze
10
+ @mysql8_pkey_error = "for key '#{event_store_events}.index_#{event_store_events}_on_event_id'".freeze
11
+ @mysql5_index_error = "for key 'index_#{event_store_events_in_streams}_on_stream_and_event_id'".freeze
12
+ @mysql8_index_error = "for key '#{event_store_events_in_streams}.index_#{event_store_events_in_streams}_on_stream_and_event_id'".freeze
13
+ @sqlite3_pkey_error = "constraint failed: #{event_store_events}.event_id".freeze
14
+ @sqlite3_index_error = "constraint failed: #{event_store_events_in_streams}.stream, #{event_store_events_in_streams}.event_id".freeze
15
+ end
14
16
 
15
17
  def detect(message)
16
- message.include?(MYSQL5_PKEY_ERROR) ||
17
- message.include?(MYSQL8_PKEY_ERROR) ||
18
- message.include?(POSTGRES_PKEY_ERROR) ||
19
- message.include?(SQLITE3_PKEY_ERROR) ||
20
-
21
- message.include?(MYSQL5_INDEX_ERROR) ||
22
- message.include?(MYSQL8_INDEX_ERROR) ||
23
- message.include?(POSTGRES_INDEX_ERROR) ||
24
- message.include?(SQLITE3_INDEX_ERROR)
18
+ detect_postgres(message) ||
19
+ detect_mysql(message) ||
20
+ detect_sqlite(message)
21
+ end
22
+
23
+ private
24
+
25
+ def detect_postgres(message)
26
+ message.include?(@postgres_pkey_error) ||
27
+ message.include?(@postgres_index_error)
28
+ end
29
+
30
+ def detect_mysql(message)
31
+ message.include?(@mysql5_pkey_error) ||
32
+ message.include?(@mysql8_pkey_error) ||
33
+ message.include?(@mysql5_index_error) ||
34
+ message.include?(@mysql8_index_error)
35
+ end
36
+
37
+ def detect_sqlite(message)
38
+ message.include?(@sqlite3_pkey_error) ||
39
+ message.include?(@sqlite3_index_error)
25
40
  end
26
41
  end
27
42
 
28
43
  private_constant(:IndexViolationDetector)
29
- end
44
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsEventStoreActiveRecord
4
- VERSION = "1.3.0"
4
+ VERSION = "2.2.0"
5
5
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsEventStoreActiveRecord
4
+ class WithAbstractBaseClass
5
+ def initialize(base_klass)
6
+ raise ArgumentError.new(
7
+ "#{base_klass} must be an abstract class that inherits from ActiveRecord::Base"
8
+ ) unless base_klass < ActiveRecord::Base && base_klass.abstract_class?
9
+ @base_klass = base_klass
10
+ end
11
+
12
+ def call(instance_id: SecureRandom.hex)
13
+ [
14
+ build_event_klass(instance_id),
15
+ build_stream_klass(instance_id),
16
+ ]
17
+ end
18
+
19
+ private
20
+ def build_event_klass(instance_id)
21
+ Object.const_set("Event_#{instance_id}",
22
+ Class.new(@base_klass) do
23
+ self.primary_key = :id
24
+ self.table_name = 'event_store_events'
25
+ end
26
+ )
27
+ end
28
+
29
+ def build_stream_klass(instance_id)
30
+ Object.const_set("EventInStream_#{instance_id}",
31
+ Class.new(@base_klass) do
32
+ self.primary_key = :id
33
+ self.table_name = 'event_store_events_in_streams'
34
+ belongs_to :event, primary_key: :event_id, class_name: "Event_#{instance_id}"
35
+ end
36
+ )
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsEventStoreActiveRecord
4
+ class WithDefaultModels
5
+ def call
6
+ [Event, EventInStream]
7
+ end
8
+ end
9
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_event_store_active_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arkency
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-15 00:00:00.000000000 Z
11
+ date: 2021-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby_event_store
@@ -16,42 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 1.3.0
19
+ version: 2.2.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 1.3.0
26
+ version: 2.2.0
27
27
  - !ruby/object:Gem::Dependency
28
- name: activesupport
28
+ name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '3.0'
33
+ version: '5.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '3.0'
41
- - !ruby/object:Gem::Dependency
42
- name: activemodel
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '3.0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '3.0'
40
+ version: '5.0'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: activerecord-import
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,42 +52,36 @@ dependencies:
66
52
  - - ">="
67
53
  - !ruby/object:Gem::Version
68
54
  version: 1.0.2
69
- description: Implementation of events repository based on Rails Active Record for
70
- Rails Event Store
71
- email:
72
- - dev@arkency.com
55
+ description: |
56
+ Persistent event repository implementation for RubyEventStore based on ActiveRecord. Ships with database schema
57
+ and migrations suitable for PostgreSQL, MySQL ans SQLite database engines.
58
+
59
+ Includes repository implementation with linearized writes to achieve log-like properties of streams
60
+ on top of SQL database engine.
61
+ email: dev@arkency.com
73
62
  executables: []
74
63
  extensions: []
75
- extra_rdoc_files: []
64
+ extra_rdoc_files:
65
+ - README.md
76
66
  files:
77
- - CHANGELOG.md
78
- - Gemfile
79
- - Makefile
80
67
  - README.md
81
- - bin/console
82
- - bin/setup
83
68
  - lib/rails_event_store_active_record.rb
84
69
  - lib/rails_event_store_active_record/batch_enumerator.rb
85
70
  - lib/rails_event_store_active_record/event.rb
86
71
  - lib/rails_event_store_active_record/event_repository.rb
87
72
  - lib/rails_event_store_active_record/event_repository_reader.rb
88
- - lib/rails_event_store_active_record/generators/binary_data_and_metadata_generator.rb
89
- - lib/rails_event_store_active_record/generators/index_by_event_type_generator.rb
90
- - lib/rails_event_store_active_record/generators/limit_for_event_id_generator.rb
91
73
  - lib/rails_event_store_active_record/generators/migration_generator.rb
92
- - lib/rails_event_store_active_record/generators/templates/binary_data_and_metadata_template.rb
93
74
  - lib/rails_event_store_active_record/generators/templates/create_event_store_events_template.rb
94
- - lib/rails_event_store_active_record/generators/templates/index_by_event_type_template.rb
95
- - lib/rails_event_store_active_record/generators/templates/limit_for_event_id_template.rb
96
75
  - lib/rails_event_store_active_record/index_violation_detector.rb
97
76
  - lib/rails_event_store_active_record/pg_linearized_event_repository.rb
98
77
  - lib/rails_event_store_active_record/version.rb
99
- - rails_event_store_active_record.gemspec
78
+ - lib/rails_event_store_active_record/with_abstract_base_class.rb
79
+ - lib/rails_event_store_active_record/with_default_models.rb
100
80
  homepage: https://railseventstore.org
101
81
  licenses:
102
82
  - MIT
103
83
  metadata:
104
- homepage_uri: https://railseventstore.org/
84
+ homepage_uri: https://railseventstore.org
105
85
  changelog_uri: https://github.com/RailsEventStore/rails_event_store/releases
106
86
  source_code_uri: https://github.com/RailsEventStore/rails_event_store
107
87
  bug_tracker_uri: https://github.com/RailsEventStore/rails_event_store/issues
@@ -113,7 +93,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
113
93
  requirements:
114
94
  - - ">="
115
95
  - !ruby/object:Gem::Version
116
- version: '0'
96
+ version: '2.6'
117
97
  required_rubygems_version: !ruby/object:Gem::Requirement
118
98
  requirements:
119
99
  - - ">="
@@ -123,5 +103,5 @@ requirements: []
123
103
  rubygems_version: 3.1.4
124
104
  signing_key:
125
105
  specification_version: 4
126
- summary: Active Record events repository for Rails Event Store
106
+ summary: Persistent event repository implementation for RubyEventStore based on ActiveRecord
127
107
  test_files: []
data/CHANGELOG.md DELETED
@@ -1,75 +0,0 @@
1
- Further changes can be tracked at [releases page](https://github.com/RailsEventStore/rails_event_store/releases).
2
-
3
- ### 0.6.14 (unreleased)
4
-
5
- * Run tests in random order
6
-
7
- ### 0.6.13 (24.08.2017)
8
-
9
- * Fix: Generate migration with version number for Rails versions that support it. Fixes compatibility with Rails 5.1.
10
-
11
- ### 0.6.12 (21.08.2017)
12
-
13
- * ruby_event_store updated to 0.14.0
14
-
15
- ### 0.6.11 (8.02.2016)
16
-
17
- * Fix: Explicit order when querying forward. Leaving it implcit to database engine choice gives different results on different engines.
18
-
19
- ### 0.6.10 (23.11.2016)
20
-
21
- * Change: requires update to allow void active_record dependency when using RailsEventStore without RailsEventStoreActiveRecord
22
-
23
- ### 0.6.9 (18.10.2016)
24
-
25
- * ruby_event_store updated to 0.13.0
26
-
27
- ### 0.6.8 (11.08.2016)
28
-
29
- * ruby_event_store updated to 0.12.1
30
- * make this gem mutant free - 100% mutation tests coverage
31
-
32
- ### 0.6.7 (10.08.2016)
33
-
34
- * ruby_event_store updated to 0.12.0
35
-
36
- ### 0.6.6 (12.07.2016)
37
-
38
- * ruby_event_store updated to 0.11.0
39
-
40
- ### 0.6.5 (12.07.2016)
41
-
42
- * ruby_event_store updated to 0.10.1
43
- * Fix: fixed bug which have made repository unable to load a event with associated data or metadata. Tests for this bug were added in ruby_event_store 0.10.1
44
-
45
- ### 0.6.4 (12.07.2016)
46
-
47
- * ruby_event_store updated to 0.10.0
48
-
49
- ### 0.6.3 (24.06.2016)
50
-
51
- * Change: ruby_event_store updated to 0.9.0 (Call instead of handle_event)
52
- * Fix: Clarify Licensing information
53
-
54
- ### 0.6.2 (21.06.2016)
55
-
56
- * ruby_event_store updated to 0.8.0
57
-
58
- ### 0.6.1 (21.06.2016)
59
-
60
- * ruby_event_store updated to 0.7.0
61
- * add indexes for commonly searched fields: time and type to migration template PR #6
62
-
63
- ### 0.6.0 (25.05.2016)
64
-
65
- * ruby_event_store updated to 0.6.0
66
-
67
- ### 0.5.1 (11.04.2016)
68
-
69
- * Change: Rename migration generator from 'migrate' to 'migration' PR #3
70
- * Change: Allow to provide a custom event class #2
71
-
72
-
73
- ### 0.5.0 (25.03.2016)
74
-
75
- * Code moved from RailsEventStore 0.5.0
data/Gemfile DELETED
@@ -1,18 +0,0 @@
1
- source 'https://rubygems.org'
2
- git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3
- gemspec
4
-
5
- eval_gemfile File.expand_path('../support/bundler/Gemfile.shared', __dir__)
6
-
7
- gem 'ruby_event_store', path: '../ruby_event_store'
8
- gem 'pg', '1.2.2'
9
- gem 'mysql2', '0.5.3'
10
- gem 'fakefs', '~> 0.11.2'
11
- gem 'childprocess'
12
- gem 'rails', ENV['RAILS_VERSION']
13
-
14
- if Gem::Version.new(ENV['RAILS_VERSION']) >= Gem::Version.new('6.0.0')
15
- gem 'sqlite3', '1.4.2'
16
- else
17
- gem 'sqlite3', '1.3.13'
18
- end
data/Makefile DELETED
@@ -1,28 +0,0 @@
1
- GEM_VERSION = $(shell cat ../RES_VERSION)
2
- GEM_NAME = rails_event_store_active_record
3
- REQUIRE = $(GEM_NAME)
4
- IGNORE = RailsEventStoreActiveRecord::IndexViolationDetector\#detect \
5
- RailsEventStoreActiveRecord::PgLinearizedEventRepository* \
6
- RailsEventStoreActiveRecord::EventRepository\#update_messages
7
- SUBJECT ?= RailsEventStoreActiveRecord*
8
- DATABASE_URL ?= sqlite3::memory:
9
-
10
- include ../support/make/install.mk
11
- include ../support/make/test.mk
12
- include ../support/make/mutant.mk
13
- include ../support/make/gem.mk
14
- include ../support/make/help.mk
15
-
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
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "rails_event_store_active_record"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
data/bin/setup DELETED
@@ -1,7 +0,0 @@
1
- #!/bin/bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
-
5
- bundle install
6
-
7
- # Do any other automated setup that you need to do here
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- begin
4
- require 'rails/generators'
5
- rescue LoadError
6
- end
7
-
8
- module RailsEventStoreActiveRecord
9
- class BinaryDataAndMetadataGenerator < Rails::Generators::Base
10
- source_root File.expand_path(File.join(File.dirname(__FILE__), '../generators/templates'))
11
-
12
- def create_migration
13
- template "binary_data_and_metadata_template.rb", "db/migrate/#{timestamp}_binary_data_and_metadata.rb"
14
- end
15
-
16
- private
17
-
18
- def rails_version
19
- Rails::VERSION::STRING
20
- end
21
-
22
- def migration_version
23
- return nil if Gem::Version.new(rails_version) < Gem::Version.new("5.0.0")
24
- "[4.2]"
25
- end
26
-
27
- def timestamp
28
- Time.now.strftime("%Y%m%d%H%M%S")
29
- end
30
- end
31
- end if defined?(Rails::Generators::Base)
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- begin
4
- require 'rails/generators'
5
- rescue LoadError
6
- end
7
-
8
- module RailsEventStoreActiveRecord
9
- class IndexByEventTypeGenerator < Rails::Generators::Base
10
- source_root File.expand_path(File.join(File.dirname(__FILE__), '../generators/templates'))
11
-
12
- def create_migration
13
- template "index_by_event_type_template.rb", "db/migrate/#{timestamp}_index_by_event_type.rb"
14
- end
15
-
16
- private
17
-
18
- def rails_version
19
- Rails::VERSION::STRING
20
- end
21
-
22
- def migration_version
23
- return nil if Gem::Version.new(rails_version) < Gem::Version.new("5.0.0")
24
- "[4.2]"
25
- end
26
-
27
- def timestamp
28
- Time.now.strftime("%Y%m%d%H%M%S")
29
- end
30
- end
31
- end if defined?(Rails::Generators::Base)
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- begin
4
- require 'rails/generators'
5
- rescue LoadError
6
- end
7
-
8
- module RailsEventStoreActiveRecord
9
- class LimitForEventIdGenerator < Rails::Generators::Base
10
- source_root File.expand_path(File.join(File.dirname(__FILE__), '../generators/templates'))
11
-
12
- def create_migration
13
- template "limit_for_event_id_template.rb", "db/migrate/#{timestamp}_limit_for_event_id.rb"
14
- end
15
-
16
- private
17
-
18
- def rails_version
19
- Rails::VERSION::STRING
20
- end
21
-
22
- def migration_version
23
- return nil if Gem::Version.new(rails_version) < Gem::Version.new("5.0.0")
24
- "[4.2]"
25
- end
26
-
27
- def timestamp
28
- Time.now.strftime("%Y%m%d%H%M%S")
29
- end
30
- end
31
- end if defined?(Rails::Generators::Base)
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class BinaryDataAndMetadata < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- rails_42 = Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new("5.0.0")
6
-
7
- case ActiveRecord::Base.connection.adapter_name
8
- when "SQLite"
9
- rename_table :event_store_events, :old_event_store_events
10
- create_table(:event_store_events, id: false, force: false) do |t|
11
- t.string :id, limit: 36, primary_key: true, null: false
12
- t.string :event_type, null: false
13
- t.binary :metadata
14
- t.binary :data, null: false
15
- t.datetime :created_at, null: false
16
- end
17
- add_index :event_store_events, :id, unique: true if rails_42
18
- add_index :event_store_events, :created_at
19
- add_index :event_store_events, :event_type
20
- execute <<-SQL
21
- INSERT INTO event_store_events(id, event_type, metadata, data, created_at)
22
- SELECT id, event_type, metadata, data, created_at FROM old_event_store_events;
23
- SQL
24
- drop_table :old_event_store_events
25
- when "PostgreSQL"
26
- execute <<-SQL
27
- ALTER TABLE event_store_events ALTER COLUMN data TYPE bytea USING convert_to(data, 'UTF8');
28
- ALTER TABLE event_store_events ALTER COLUMN metadata TYPE bytea USING convert_to(metadata, 'UTF8');
29
- SQL
30
- else
31
- change_column :event_store_events, :data, :binary
32
- change_column :event_store_events, :metadata, :binary
33
- end
34
- end
35
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class IndexByEventType < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- add_index :event_store_events, :event_type unless index_exists? :event_store_events, :event_type
6
- end
7
- end
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class LimitForEventId < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- postgres = ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
6
- change_column(:event_store_events_in_streams, :event_id, :string, limit: 36) unless postgres
7
- end
8
- end
@@ -1,32 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'rails_event_store_active_record/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = 'rails_event_store_active_record'
8
- spec.version = RailsEventStoreActiveRecord::VERSION
9
- spec.licenses = ['MIT']
10
- spec.authors = ['Arkency']
11
- spec.email = ['dev@arkency.com']
12
-
13
- spec.summary = %q{Active Record events repository for Rails Event Store}
14
- spec.description = %q{Implementation of events repository based on Rails Active Record for Rails Event Store}
15
- spec.homepage = 'https://railseventstore.org'
16
- spec.metadata = {
17
- "homepage_uri" => "https://railseventstore.org/",
18
- "changelog_uri" => "https://github.com/RailsEventStore/rails_event_store/releases",
19
- "source_code_uri" => "https://github.com/RailsEventStore/rails_event_store",
20
- "bug_tracker_uri" => "https://github.com/RailsEventStore/rails_event_store/issues",
21
- }
22
-
23
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
- spec.bindir = 'exe'
25
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
- spec.require_paths = ['lib']
27
-
28
- spec.add_dependency 'ruby_event_store', '= 1.3.0'
29
- spec.add_dependency 'activesupport', '>= 3.0'
30
- spec.add_dependency 'activemodel', '>= 3.0'
31
- spec.add_dependency 'activerecord-import', '>= 1.0.2'
32
- end