ruby_event_store-rom 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +4 -0
- data/Makefile +78 -0
- data/README.md +9 -0
- data/Rakefile +20 -0
- data/db/migrate/20180327044629_create_ruby_event_store_tables.rb +45 -0
- data/lib/ruby_event_store-rom.rb +1 -0
- data/lib/ruby_event_store/rom.rb +107 -0
- data/lib/ruby_event_store/rom/adapters/sql/index_violation_detector.rb +26 -0
- data/lib/ruby_event_store/rom/adapters/sql/rake_task.rb +3 -0
- data/lib/ruby_event_store/rom/adapters/sql/relations/events.rb +11 -0
- data/lib/ruby_event_store/rom/adapters/sql/relations/stream_entries.rb +61 -0
- data/lib/ruby_event_store/rom/adapters/sql/tasks/migration_tasks.rake +18 -0
- data/lib/ruby_event_store/rom/adapters/sql/unit_of_work.rb +37 -0
- data/lib/ruby_event_store/rom/event_repository.rb +91 -0
- data/lib/ruby_event_store/rom/mappers/event_to_serialized_record.rb +18 -0
- data/lib/ruby_event_store/rom/mappers/stream_entry_to_serialized_record.rb +18 -0
- data/lib/ruby_event_store/rom/repositories/events.rb +53 -0
- data/lib/ruby_event_store/rom/repositories/stream_entries.rb +48 -0
- data/lib/ruby_event_store/rom/sql.rb +81 -0
- data/lib/ruby_event_store/rom/tuple_uniqueness_error.rb +6 -0
- data/lib/ruby_event_store/rom/unit_of_work.rb +23 -0
- data/lib/ruby_event_store/rom/version.rb +5 -0
- data/ruby_event_store-rom.gemspec +44 -0
- metadata +282 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: daa7bf0e1b646617b35f359cbef1a2160c486cd72cef8e6865f38bd2d6bc8dbf
|
4
|
+
data.tar.gz: 7262de3e82f5e5ed7de6955a4d4973ba1f04dc8b877c74b38b7f804867d26479
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5ec50cdeb365d38b2420af3736fa994c40670a6a703677fb1348dd3c1e26909407b2d04376d43e156428e989aca08a7d508411625589efee0b5f39224c04506f
|
7
|
+
data.tar.gz: e25e06dcd18b2a4f071d89804ac7a68d1cb7275457f8114ddc22a8af9e0a42aa858833e50c3f81a0e69294913692a9357fd7b914e8e3f7aa014c3510cdbe65c6
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Further changes can be tracked at [releases page](https://github.com/RailsEventStore/rails_event_store/releases).
|
2
|
+
|
3
|
+
### 0.1.0 (03.04.2018)
|
4
|
+
|
5
|
+
* Implemented ROM SQL adapter
|
6
|
+
* Add `rom-sql` 2.4.0 dependency
|
7
|
+
* Add `rom-repository` 2.0.2 dependency
|
8
|
+
* Add `rom-changeset` 1.0.2 dependency
|
9
|
+
* Add `sequel` 4.49 dependency
|
data/Gemfile
ADDED
data/Makefile
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
GEM_VERSION = $(shell cat ../RES_VERSION)
|
2
|
+
GEM_NAME = ruby_event_store-rom
|
3
|
+
REQUIRE = $(GEM_NAME)
|
4
|
+
IGNORE = RubyEventStore::ROM::EventRepository\#handle_not_found_errors \
|
5
|
+
RubyEventStore::ROM::EventRepository\#handle_unique_violation_errors \
|
6
|
+
RubyEventStore::ROM::EventRepository\#has_event? \
|
7
|
+
RubyEventStore::ROM::EventRepository\#last_stream_event \
|
8
|
+
RubyEventStore::ROM::Repositories::Events\#find_nonexistent_pks \
|
9
|
+
RubyEventStore::ROM::Env\#handle_error \
|
10
|
+
RubyEventStore::ROM::Env\#initialize \
|
11
|
+
RubyEventStore::ROM::Env\#register_error_handler \
|
12
|
+
RubyEventStore::ROM::Env\#register_unit_of_work_options \
|
13
|
+
RubyEventStore::ROM::Env\#transaction \
|
14
|
+
RubyEventStore::ROM::UnitOfWork\#call \
|
15
|
+
RubyEventStore::ROM::UnitOfWork\#commit! \
|
16
|
+
RubyEventStore::ROM::SQL::Relations::StreamEntries\#normalize_stream_name \
|
17
|
+
RubyEventStore::ROM::SQL::IndexViolationDetector\#detect \
|
18
|
+
RubyEventStore::ROM::SQL::SpecHelper\#load_gateway_schema \
|
19
|
+
RubyEventStore::ROM::SQL::SpecHelper\#establish_gateway_connection \
|
20
|
+
RubyEventStore::ROM::SQL::SpecHelper\#drop_gateway_schema \
|
21
|
+
RubyEventStore::ROM::SQL::SpecHelper\#close_gateway_connection \
|
22
|
+
RubyEventStore::ROM::SQL::UnitOfWork\#commit!
|
23
|
+
SUBJECT ?= RubyEventStore::ROM*
|
24
|
+
DATABASE_URL ?= sqlite::memory:
|
25
|
+
|
26
|
+
install: ## Install gem dependencies
|
27
|
+
@echo "Installing gem dependencies"
|
28
|
+
@bundle install
|
29
|
+
|
30
|
+
remove-lock:
|
31
|
+
@echo "Removing resolved dependency versions"
|
32
|
+
-rm Gemfile.lock
|
33
|
+
|
34
|
+
reinstall: remove-lock install ## Removing resolved dependency versions
|
35
|
+
|
36
|
+
test: ## Run unit tests
|
37
|
+
@echo "Running unit tests"
|
38
|
+
@bundle exec rspec
|
39
|
+
|
40
|
+
test-fast: ## Run unit tests with --fail-fast
|
41
|
+
@echo "Running unit tests with --fail-fast"
|
42
|
+
@bundle exec rspec --fail-fast --order defined --backtrace
|
43
|
+
|
44
|
+
mutate: test ## Run mutation tests
|
45
|
+
@echo "Running mutation tests"
|
46
|
+
@DATABASE_URL=$(DATABASE_URL) bundle exec mutant --include lib \
|
47
|
+
$(addprefix --require ,$(REQUIRE)) \
|
48
|
+
$(addprefix --ignore-subject ,$(IGNORE)) \
|
49
|
+
--use rspec "$(SUBJECT)"
|
50
|
+
|
51
|
+
mutate-fast: ## Run mutation tests with --fail-fast
|
52
|
+
@echo "Running mutation tests with --fail-fast"
|
53
|
+
@DATABASE_URL=$(DATABASE_URL) bundle exec mutant --include lib \
|
54
|
+
$(addprefix --require ,$(REQUIRE)) \
|
55
|
+
$(addprefix --ignore-subject ,$(IGNORE)) \
|
56
|
+
--fail-fast \
|
57
|
+
--use rspec "$(SUBJECT)"
|
58
|
+
|
59
|
+
build:
|
60
|
+
@echo "Building gem package"
|
61
|
+
@gem build -V $(GEM_NAME).gemspec
|
62
|
+
@mkdir -p pkg/
|
63
|
+
@mv $(GEM_NAME)-$(GEM_VERSION).gem pkg/
|
64
|
+
|
65
|
+
push:
|
66
|
+
@echo "Pushing package to RubyGems"
|
67
|
+
@gem push -k dev_arkency pkg/$(GEM_NAME)-$(GEM_VERSION).gem
|
68
|
+
|
69
|
+
clean:
|
70
|
+
@echo "Removing previously built package"
|
71
|
+
-rm pkg/$(GEM_NAME)-$(GEM_VERSION).gem
|
72
|
+
|
73
|
+
help:
|
74
|
+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
75
|
+
|
76
|
+
.PHONY: help
|
77
|
+
.DEFAULT_GOAL := help
|
78
|
+
|
data/README.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# RubyEventStore ROM Event Repository
|
2
|
+
|
3
|
+
A Ruby Object Model (ROM) implementation of events repository for [Ruby Event Store](https://github.com/RailsEventStore/rails_event_store).
|
4
|
+
|
5
|
+
This version of the ROM adapter supports [rom-sql](https://github.com/rom-rb/rom-sql) at this time. It is an alternative to the ActiveRecord `EventRepository` implementation used in `rails_event_store` gem.
|
6
|
+
|
7
|
+
[Read the docs to get started.](http://railseventstore.org/docs/repository/)
|
8
|
+
|
9
|
+
_Additonal backing stores via ROM are being tracked here: [#299](https://github.com/RailsEventStore/rails_event_store/issues/299)._
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'ruby_event_store/rom/adapters/sql/rake_task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
task default: [:ci]
|
7
|
+
|
8
|
+
desc "Run CI tasks"
|
9
|
+
task ci: [:spec]
|
10
|
+
|
11
|
+
begin
|
12
|
+
require "rubocop/rake_task"
|
13
|
+
|
14
|
+
Rake::Task[:default].enhance [:rubocop]
|
15
|
+
|
16
|
+
RuboCop::RakeTask.new do |task|
|
17
|
+
task.options << "--display-cop-names"
|
18
|
+
end
|
19
|
+
rescue LoadError
|
20
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rom/sql'
|
2
|
+
|
3
|
+
::ROM::SQL.migration do
|
4
|
+
change do
|
5
|
+
postgres = database_type =~ /postgres/
|
6
|
+
sqlite = database_type =~ /sqlite/
|
7
|
+
|
8
|
+
run 'CREATE EXTENSION IF NOT EXISTS pgcrypto;' if postgres
|
9
|
+
|
10
|
+
create_table? :event_store_events_in_streams do
|
11
|
+
primary_key :id, type: :Bignum, null: false
|
12
|
+
|
13
|
+
column :stream, String, null: false
|
14
|
+
column :position, Integer
|
15
|
+
|
16
|
+
if postgres
|
17
|
+
column :event_id, :uuid, null: false
|
18
|
+
else
|
19
|
+
column :event_id, String, size: 36, null: false
|
20
|
+
end
|
21
|
+
|
22
|
+
column :created_at, DateTime, null: false, index: 'index_event_store_events_in_streams_on_created_at'
|
23
|
+
|
24
|
+
index %i[stream position], unique: true, name: 'index_event_store_events_in_streams_on_stream_and_position'
|
25
|
+
index %i[stream event_id], unique: true, name: 'index_event_store_events_in_streams_on_stream_and_event_id'
|
26
|
+
end
|
27
|
+
|
28
|
+
create_table? :event_store_events do
|
29
|
+
if postgres
|
30
|
+
column :id, :uuid, default: Sequel.function(:gen_random_uuid), primary_key: true
|
31
|
+
else
|
32
|
+
column :id, String, size: 36, null: false, primary_key: true
|
33
|
+
end
|
34
|
+
|
35
|
+
column :event_type, String, null: false
|
36
|
+
column :metadata, String, text: true
|
37
|
+
column :data, String, text: true, null: false
|
38
|
+
column :created_at, DateTime, null: false, index: 'index_event_store_events_on_created_at'
|
39
|
+
|
40
|
+
if sqlite # TODO: Is this relevant without ActiveRecord?
|
41
|
+
index :id, unique: true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'ruby_event_store/rom'
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'rom-changeset'
|
2
|
+
require 'rom-mapper'
|
3
|
+
require 'rom-repository'
|
4
|
+
require 'ruby_event_store'
|
5
|
+
require 'ruby_event_store/rom/event_repository'
|
6
|
+
require 'ruby_event_store/rom/tuple_uniqueness_error'
|
7
|
+
require 'ruby_event_store/rom/unit_of_work'
|
8
|
+
require 'ruby_event_store/rom/version'
|
9
|
+
|
10
|
+
module RubyEventStore
|
11
|
+
module ROM
|
12
|
+
class Env
|
13
|
+
attr_accessor :container
|
14
|
+
|
15
|
+
def initialize(container)
|
16
|
+
@container = container
|
17
|
+
|
18
|
+
container.register(:unique_violation_error_handlers, Set.new)
|
19
|
+
container.register(:not_found_error_handlers, Set.new)
|
20
|
+
container.register(:logger, Logger.new(STDOUT).tap { |logger| logger.level = Logger::WARN })
|
21
|
+
end
|
22
|
+
|
23
|
+
def logger
|
24
|
+
container[:logger]
|
25
|
+
end
|
26
|
+
|
27
|
+
def transaction(&block)
|
28
|
+
options = container[:unit_of_work_options].dup
|
29
|
+
options.delete(:class){UnitOfWork}.new(rom: self).call(**options, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def register_unit_of_work_options(options)
|
33
|
+
container.register(:unit_of_work_options, options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def register_error_handler(type, handler)
|
37
|
+
container[:"#{type}_error_handlers"] << handler
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_error(type, ex, *args)
|
41
|
+
container[:"#{type}_error_handlers"].each{ |h| h.call(ex, *args) }
|
42
|
+
raise ex
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
# Set to a default instance
|
48
|
+
attr_accessor :env
|
49
|
+
|
50
|
+
def configure(adapter_name, database_uri = ENV['DATABASE_URL'], &block)
|
51
|
+
if adapter_name.is_a?(::ROM::Configuration)
|
52
|
+
# Call config block manually
|
53
|
+
Env.new ::ROM.container(adapter_name.tap(&block), &block)
|
54
|
+
elsif database_uri.nil?
|
55
|
+
raise ArgumentError.new('Missing database URI argument or DATABASE_URL environment variable')
|
56
|
+
else
|
57
|
+
Env.new ::ROM.container(adapter_name, database_uri, &block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def setup(*args, &block)
|
62
|
+
configure(*args) do |config|
|
63
|
+
setup_defaults(config)
|
64
|
+
block.call(config) if block
|
65
|
+
end.tap(&method(:configure_defaults))
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def setup_defaults(config)
|
71
|
+
require_relative 'rom/repositories/stream_entries'
|
72
|
+
require_relative 'rom/repositories/events'
|
73
|
+
|
74
|
+
config.register_mapper(ROM::Mappers::EventToSerializedRecord)
|
75
|
+
config.register_mapper(ROM::Mappers::StreamEntryToSerializedRecord)
|
76
|
+
|
77
|
+
find_adapters(config.environment.gateways).each do |adapter|
|
78
|
+
adapter.setup(config)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def configure_defaults(env)
|
83
|
+
env.register_error_handler :not_found, -> (ex, event_id) {
|
84
|
+
case ex
|
85
|
+
when ::ROM::TupleCountMismatchError
|
86
|
+
raise EventNotFound.new(event_id)
|
87
|
+
end
|
88
|
+
}
|
89
|
+
|
90
|
+
find_adapters(env.container.gateways).each do |adapter|
|
91
|
+
adapter.configure(env)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def find_adapters(gateways)
|
96
|
+
# Setup for each kind of gateway class
|
97
|
+
gateways.values.map(&:class).uniq.map do |klass|
|
98
|
+
constant = klass.name.split('::')[1].to_sym
|
99
|
+
|
100
|
+
next unless RubyEventStore::ROM.constants.include?(constant)
|
101
|
+
|
102
|
+
RubyEventStore::ROM.const_get(constant)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module ROM
|
3
|
+
module SQL
|
4
|
+
class IndexViolationDetector
|
5
|
+
|
6
|
+
MYSQL_PKEY_ERROR = "for key 'PRIMARY'"
|
7
|
+
POSTGRES_PKEY_ERROR = "event_store_events_pkey"
|
8
|
+
SQLITE3_PKEY_ERROR = "event_store_events.id"
|
9
|
+
|
10
|
+
MYSQL_INDEX_ERROR = "for key 'index_event_store_events_in_streams_on_stream_and_event_id'"
|
11
|
+
POSTGRES_INDEX_ERROR = "Key (stream, event_id)"
|
12
|
+
SQLITE3_INDEX_ERROR = "event_store_events_in_streams.stream, event_store_events_in_streams.event_id"
|
13
|
+
|
14
|
+
def detect(message)
|
15
|
+
message.include?(MYSQL_PKEY_ERROR) ||
|
16
|
+
message.include?(POSTGRES_PKEY_ERROR) ||
|
17
|
+
message.include?(SQLITE3_PKEY_ERROR) ||
|
18
|
+
|
19
|
+
message.include?(MYSQL_INDEX_ERROR) ||
|
20
|
+
message.include?(POSTGRES_INDEX_ERROR) ||
|
21
|
+
message.include?(SQLITE3_INDEX_ERROR)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module ROM
|
3
|
+
module SQL
|
4
|
+
module Relations
|
5
|
+
class StreamEntries < ::ROM::Relation[:sql]
|
6
|
+
schema(:event_store_events_in_streams, as: :stream_entries, infer: true) do
|
7
|
+
associations do
|
8
|
+
belongs_to :events, as: :event, foreign_key: :event_id
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method :take, :limit
|
13
|
+
|
14
|
+
def by_stream(stream)
|
15
|
+
where(stream: stream.name)
|
16
|
+
end
|
17
|
+
|
18
|
+
SERIALIZED_GLOBAL_STREAM_NAME = 'all'.freeze
|
19
|
+
|
20
|
+
def by_stream(stream)
|
21
|
+
where(stream: normalize_stream_name(stream))
|
22
|
+
end
|
23
|
+
|
24
|
+
def by_stream_and_event_id(stream, event_id)
|
25
|
+
where(stream: normalize_stream_name(stream), event_id: event_id).one!
|
26
|
+
end
|
27
|
+
|
28
|
+
def max_position(stream)
|
29
|
+
by_stream(stream).select(:position).order(Sequel.desc(:position)).first
|
30
|
+
end
|
31
|
+
|
32
|
+
DIRECTION_MAP = {
|
33
|
+
forward: [:asc, :>],
|
34
|
+
backward: [:desc, :<]
|
35
|
+
}.freeze
|
36
|
+
|
37
|
+
def ordered(direction, stream, offset_entry_id = nil)
|
38
|
+
order, operator = DIRECTION_MAP[direction]
|
39
|
+
|
40
|
+
raise ArgumentError, 'Direction must be :forward or :backward' if order.nil?
|
41
|
+
|
42
|
+
order_columns = %i[position id]
|
43
|
+
order_columns.delete(:position) if stream.global?
|
44
|
+
|
45
|
+
query = by_stream(stream)
|
46
|
+
query = query.where { id.public_send(operator, offset_entry_id) } if offset_entry_id
|
47
|
+
query.order { |r| order_columns.map { |c| r[:stream_entries][c].public_send(order) } }
|
48
|
+
end
|
49
|
+
|
50
|
+
alias_method :take, :limit
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def normalize_stream_name(stream)
|
55
|
+
stream.global? ? SERIALIZED_GLOBAL_STREAM_NAME : stream.name
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'ruby_event_store/rom/sql'
|
2
|
+
|
3
|
+
desc 'Setup ROM EventRespository environment'
|
4
|
+
task 'db:setup' do
|
5
|
+
ROM::SQL::RakeSupport.env = ::RubyEventStore::ROM.configure(:sql).container
|
6
|
+
end
|
7
|
+
|
8
|
+
desc "Copy RubyEventStore SQL migrations to db/migrate"
|
9
|
+
task 'db:copy_migrations' => 'db:setup' do
|
10
|
+
Dir[File.join(File.dirname(__FILE__), '../../../../../../db/migrate/*.rb')].each do |input|
|
11
|
+
name = File.basename(input, '.*').sub(/\d+_/, '')
|
12
|
+
output = ROM::SQL::RakeSupport.create_migration(name)
|
13
|
+
|
14
|
+
File.write output, File.read(input)
|
15
|
+
|
16
|
+
puts "<= migration file created #{output}"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module ROM
|
3
|
+
module SQL
|
4
|
+
class UnitOfWork < ROM::UnitOfWork
|
5
|
+
def commit!(gateway, changesets, **options)
|
6
|
+
# Committing changesets concurrently causes MySQL deadlocks
|
7
|
+
# which are not caught and retried by Sequel's built-in
|
8
|
+
# :retry_on option. This appears to be a result of how ROM
|
9
|
+
# handles exceptions which don't bubble up so that Sequel
|
10
|
+
# can retry transactions with the :retry_on option when there's
|
11
|
+
# a deadlock.
|
12
|
+
#
|
13
|
+
# This is exacerbated by the fact that changesets insert multiple
|
14
|
+
# tuples with individual INSERT statements because ROM specifies
|
15
|
+
# to Sequel to return a list of primary keys created. The likelihood
|
16
|
+
# of a deadlock is reduced with batched INSERT statements.
|
17
|
+
#
|
18
|
+
# For this reason we need to manually insert changeset records to avoid
|
19
|
+
# MySQL deadlocks or to allow Sequel to retry transactions
|
20
|
+
# when the :retry_on option is specified.
|
21
|
+
options.merge!(
|
22
|
+
retry_on: Sequel::SerializationFailure,
|
23
|
+
before_retry: -> (num, ex) {
|
24
|
+
env.logger.warn("RETRY TRANSACTION [#{self.class.name} => #{ex.class.name}] #{ex.message}")
|
25
|
+
}
|
26
|
+
)
|
27
|
+
|
28
|
+
gateway.transaction(options) do
|
29
|
+
changesets.each do |changeset|
|
30
|
+
changeset.relation.multi_insert(changeset.to_a)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'ruby_event_store/rom/unit_of_work'
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
module ROM
|
5
|
+
class EventRepository
|
6
|
+
def initialize(rom: ROM.env)
|
7
|
+
@rom = rom
|
8
|
+
@events = Repositories::Events.new(rom.container)
|
9
|
+
@stream_entries = Repositories::StreamEntries.new(rom.container)
|
10
|
+
end
|
11
|
+
|
12
|
+
def append_to_stream(events, stream, expected_version)
|
13
|
+
events = normalize_to_array(events)
|
14
|
+
event_ids = events.map(&:event_id)
|
15
|
+
|
16
|
+
@rom.transaction do |changesets|
|
17
|
+
# Create changesets inside transaction because
|
18
|
+
# we want to find the last position (a.k.a. version)
|
19
|
+
# again if the transaction is retried due to a
|
20
|
+
# deadlock in MySQL
|
21
|
+
changesets << @events.create_changeset(events)
|
22
|
+
changesets << @stream_entries.create_changeset(event_ids, stream, expected_version, global_stream: true)
|
23
|
+
end
|
24
|
+
|
25
|
+
self
|
26
|
+
rescue => ex
|
27
|
+
@rom.handle_error(:unique_violation, ex)
|
28
|
+
end
|
29
|
+
|
30
|
+
def link_to_stream(event_ids, stream, expected_version)
|
31
|
+
event_ids = normalize_to_array(event_ids)
|
32
|
+
nonexistent_ids = @events.find_nonexistent_pks(event_ids)
|
33
|
+
|
34
|
+
nonexistent_ids.each { |id| raise EventNotFound.new(id) }
|
35
|
+
|
36
|
+
@stream_entries.create_changeset(event_ids, stream, expected_version).commit
|
37
|
+
|
38
|
+
self
|
39
|
+
rescue => ex
|
40
|
+
@rom.handle_error(:unique_violation, ex)
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete_stream(stream)
|
44
|
+
@stream_entries.delete(stream)
|
45
|
+
end
|
46
|
+
|
47
|
+
def has_event?(event_id)
|
48
|
+
@events.exist?(event_id)
|
49
|
+
rescue => ex
|
50
|
+
begin
|
51
|
+
@rom.handle_error(:not_found, ex, event_id)
|
52
|
+
rescue EventNotFound
|
53
|
+
false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def last_stream_event(stream)
|
58
|
+
Specification.new(self)
|
59
|
+
.stream(stream.name)
|
60
|
+
.limit(1)
|
61
|
+
.backward
|
62
|
+
.each
|
63
|
+
.first
|
64
|
+
end
|
65
|
+
|
66
|
+
def read_event(event_id)
|
67
|
+
@events.by_id(event_id)
|
68
|
+
rescue => ex
|
69
|
+
@rom.handle_error(:not_found, ex, event_id)
|
70
|
+
end
|
71
|
+
|
72
|
+
def read(specification)
|
73
|
+
raise ReservedInternalName if specification.stream_name.eql?(@stream_entries.stream_entries.class::SERIALIZED_GLOBAL_STREAM_NAME)
|
74
|
+
|
75
|
+
@events.read(
|
76
|
+
specification.direction,
|
77
|
+
specification.stream,
|
78
|
+
from: specification.start,
|
79
|
+
limit: (specification.count if specification.limit?)
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def normalize_to_array(events)
|
86
|
+
return events if events.is_a?(Enumerable)
|
87
|
+
[events]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rom/transformer'
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
module ROM
|
5
|
+
module Mappers
|
6
|
+
class EventToSerializedRecord < ::ROM::Transformer
|
7
|
+
relation :events
|
8
|
+
register_as :event_to_serialized_record
|
9
|
+
|
10
|
+
map_array do
|
11
|
+
rename_keys id: :event_id
|
12
|
+
accept_keys %i[event_id data metadata event_type]
|
13
|
+
constructor_inject RubyEventStore::SerializedRecord
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rom/transformer'
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
module ROM
|
5
|
+
module Mappers
|
6
|
+
class StreamEntryToSerializedRecord < ::ROM::Transformer
|
7
|
+
relation :stream_entries
|
8
|
+
register_as :stream_entry_to_serialized_record
|
9
|
+
|
10
|
+
map_array do
|
11
|
+
unwrap :event, %i[data metadata event_type]
|
12
|
+
accept_keys %i[event_id data metadata event_type]
|
13
|
+
constructor_inject RubyEventStore::SerializedRecord
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative '../mappers/event_to_serialized_record'
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
module ROM
|
5
|
+
module Repositories
|
6
|
+
class Events < ::ROM::Repository[:events]
|
7
|
+
class Create < ::ROM::Changeset::Create
|
8
|
+
# Convert to Hash
|
9
|
+
map(&:to_h)
|
10
|
+
|
11
|
+
map do
|
12
|
+
rename_keys event_id: :id
|
13
|
+
accept_keys %i[id data metadata event_type]
|
14
|
+
end
|
15
|
+
|
16
|
+
map do |tuple|
|
17
|
+
Hash(created_at: Time.now).merge(tuple)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_changeset(serialized_records)
|
22
|
+
events.changeset(Create, serialized_records)
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_nonexistent_pks(event_ids)
|
26
|
+
return event_ids unless event_ids.any?
|
27
|
+
event_ids - events.by_pk(event_ids).pluck(:id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def exist?(event_id)
|
31
|
+
events.by_pk(event_id).exist?
|
32
|
+
end
|
33
|
+
|
34
|
+
def by_id(event_id)
|
35
|
+
events.map_with(:event_to_serialized_record).by_pk(event_id).one!
|
36
|
+
end
|
37
|
+
|
38
|
+
def read(direction, stream, from:, limit:)
|
39
|
+
unless from.equal?(:head)
|
40
|
+
offset_entry_id = stream_entries.by_stream_and_event_id(stream, from).fetch(:id)
|
41
|
+
end
|
42
|
+
|
43
|
+
stream_entries
|
44
|
+
.ordered(direction, stream, offset_entry_id)
|
45
|
+
.take(limit)
|
46
|
+
.combine(:event)
|
47
|
+
.map_with(:stream_entry_to_serialized_record) # Add `auto_struct: false` for Memory adapter
|
48
|
+
.each
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative '../mappers/stream_entry_to_serialized_record'
|
2
|
+
|
3
|
+
module RubyEventStore
|
4
|
+
module ROM
|
5
|
+
module Repositories
|
6
|
+
class StreamEntries < ::ROM::Repository[:stream_entries]
|
7
|
+
class Create < ::ROM::Changeset::Create
|
8
|
+
map do |tuple|
|
9
|
+
Hash(created_at: Time.now).merge(tuple)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
POSITION_SHIFT = 1.freeze
|
14
|
+
|
15
|
+
def create_changeset(event_ids, stream, expected_version, global_stream: nil)
|
16
|
+
resolved_version = expected_version.resolve_for(stream, ->(_stream) {
|
17
|
+
(stream_entries.max_position(stream) || {})[:position]
|
18
|
+
})
|
19
|
+
|
20
|
+
tuples = []
|
21
|
+
|
22
|
+
event_ids.each_with_index do |event_id, index|
|
23
|
+
tuples << {
|
24
|
+
stream: stream.name,
|
25
|
+
position: resolved_version && resolved_version + index + POSITION_SHIFT,
|
26
|
+
event_id: event_id
|
27
|
+
} unless stream.global?
|
28
|
+
|
29
|
+
tuples << {
|
30
|
+
stream: stream_entries.class::SERIALIZED_GLOBAL_STREAM_NAME,
|
31
|
+
event_id: event_id
|
32
|
+
} if global_stream
|
33
|
+
end
|
34
|
+
|
35
|
+
stream_entries.changeset(Create, tuples)
|
36
|
+
end
|
37
|
+
|
38
|
+
def delete(stream)
|
39
|
+
delete_changeset(stream).commit
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete_changeset(stream)
|
43
|
+
stream_entries.by_stream(stream).changeset(:delete)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'rom/sql'
|
2
|
+
require 'ruby_event_store/rom'
|
3
|
+
require_relative 'adapters/sql/index_violation_detector'
|
4
|
+
require_relative 'adapters/sql/unit_of_work'
|
5
|
+
require_relative 'adapters/sql/relations/events'
|
6
|
+
require_relative 'adapters/sql/relations/stream_entries'
|
7
|
+
|
8
|
+
module RubyEventStore
|
9
|
+
module ROM
|
10
|
+
module SQL
|
11
|
+
class << self
|
12
|
+
def setup(config)
|
13
|
+
config.register_relation Relations::Events
|
14
|
+
config.register_relation Relations::StreamEntries
|
15
|
+
end
|
16
|
+
|
17
|
+
def configure(env)
|
18
|
+
# See: https://github.com/jeremyevans/sequel/blob/master/doc/transactions.rdoc
|
19
|
+
env.register_unit_of_work_options(
|
20
|
+
class: UnitOfWork,
|
21
|
+
savepoint: true
|
22
|
+
)
|
23
|
+
|
24
|
+
env.register_error_handler :unique_violation, -> ex {
|
25
|
+
case ex
|
26
|
+
when ::ROM::SQL::UniqueConstraintError, Sequel::UniqueConstraintViolation
|
27
|
+
raise EventDuplicatedInStream if IndexViolationDetector.new.detect(ex.message)
|
28
|
+
raise WrongExpectedEventVersion
|
29
|
+
end
|
30
|
+
}
|
31
|
+
|
32
|
+
env.register_error_handler :not_found, -> (ex, event_id) {
|
33
|
+
case ex
|
34
|
+
when ::ROM::TupleCountMismatchError
|
35
|
+
raise EventNotFound.new(event_id)
|
36
|
+
when Sequel::DatabaseError
|
37
|
+
raise ex unless ex.message =~ /PG::InvalidTextRepresentation.*uuid/
|
38
|
+
raise EventNotFound.new(event_id)
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class SpecHelper
|
45
|
+
attr_reader :env
|
46
|
+
|
47
|
+
def initialize(rom: ROM.env)
|
48
|
+
@env = rom
|
49
|
+
end
|
50
|
+
|
51
|
+
def gateway
|
52
|
+
env.container.gateways.fetch(:default)
|
53
|
+
end
|
54
|
+
|
55
|
+
def establish_gateway_connection
|
56
|
+
# Manually preconnect because disconnecting and reconnecting
|
57
|
+
# seems to lose the "preconnect concurrently" setting
|
58
|
+
gateway.connection.pool.send(:preconnect, true)
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_gateway_schema
|
62
|
+
gateway.run_migrations
|
63
|
+
end
|
64
|
+
|
65
|
+
def drop_gateway_schema
|
66
|
+
gateway.connection.drop_table?('event_store_events')
|
67
|
+
gateway.connection.drop_table?('event_store_events_in_streams')
|
68
|
+
gateway.connection.drop_table?('schema_migrations')
|
69
|
+
end
|
70
|
+
|
71
|
+
# See: https://github.com/rom-rb/rom-sql/blob/master/spec/shared/database_setup.rb
|
72
|
+
def close_gateway_connection
|
73
|
+
gateway.connection.disconnect
|
74
|
+
# Prevent the auto-reconnect when the test completed
|
75
|
+
# This will save from hardly reproducible connection run outs
|
76
|
+
gateway.connection.pool.available_connections.freeze
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module ROM
|
3
|
+
class UnitOfWork
|
4
|
+
attr_reader :env
|
5
|
+
|
6
|
+
def initialize(rom: ROM.env)
|
7
|
+
@env = rom
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(**options)
|
11
|
+
gateway = @env.container.gateways.fetch(options.delete(:gateway){:default})
|
12
|
+
|
13
|
+
yield(changesets = [])
|
14
|
+
|
15
|
+
commit!(gateway, changesets, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def commit!(gateway, changesets, **options)
|
19
|
+
gateway.transaction(options) { changesets.each(&:commit) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ruby_event_store/rom/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'ruby_event_store-rom'
|
8
|
+
spec.version = RubyEventStore::ROM::VERSION
|
9
|
+
spec.licenses = ['MIT']
|
10
|
+
spec.authors = ['Joel Van Horn']
|
11
|
+
spec.email = ['joel@joelvanhorn.com']
|
12
|
+
|
13
|
+
spec.summary = %q{ROM events repository for Ruby Event Store}
|
14
|
+
spec.description = %q{Implementation of events repository based on ROM for Ruby 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_development_dependency 'bundler', '~> 1.15'
|
29
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
30
|
+
spec.add_development_dependency 'rspec', '~> 3.6'
|
31
|
+
spec.add_development_dependency 'sqlite3', '1.3.13'
|
32
|
+
spec.add_development_dependency 'pg', '0.21'
|
33
|
+
spec.add_development_dependency 'mysql2', '0.4.10'
|
34
|
+
spec.add_development_dependency 'mutant-rspec', '~> 0.8.14'
|
35
|
+
spec.add_development_dependency 'fakefs', '~> 0.11.2'
|
36
|
+
spec.add_development_dependency 'childprocess'
|
37
|
+
spec.add_development_dependency 'google-protobuf', '~> 3.5.1.2'
|
38
|
+
|
39
|
+
spec.add_dependency 'ruby_event_store', '= 0.28.0'
|
40
|
+
spec.add_dependency 'sequel', '>= 4.49'
|
41
|
+
spec.add_dependency 'rom-sql', '~> 2.4'
|
42
|
+
spec.add_dependency 'rom-repository', '~> 2.0'
|
43
|
+
spec.add_dependency 'rom-changeset', '~> 1.0'
|
44
|
+
end
|
metadata
ADDED
@@ -0,0 +1,282 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_event_store-rom
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.28.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joel Van Horn
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-05-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.15'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.6'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sqlite3
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.3.13
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.3.13
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pg
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.21'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.21'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: mysql2
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.4.10
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.4.10
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: mutant-rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.8.14
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.8.14
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: fakefs
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.11.2
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.11.2
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: childprocess
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: google-protobuf
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 3.5.1.2
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 3.5.1.2
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: ruby_event_store
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - '='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 0.28.0
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - '='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 0.28.0
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: sequel
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '4.49'
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '4.49'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: rom-sql
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '2.4'
|
188
|
+
type: :runtime
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - "~>"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '2.4'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: rom-repository
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - "~>"
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '2.0'
|
202
|
+
type: :runtime
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '2.0'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: rom-changeset
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - "~>"
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '1.0'
|
216
|
+
type: :runtime
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - "~>"
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '1.0'
|
223
|
+
description: Implementation of events repository based on ROM for Ruby Event Store'
|
224
|
+
email:
|
225
|
+
- joel@joelvanhorn.com
|
226
|
+
executables: []
|
227
|
+
extensions: []
|
228
|
+
extra_rdoc_files: []
|
229
|
+
files:
|
230
|
+
- CHANGELOG.md
|
231
|
+
- Gemfile
|
232
|
+
- Makefile
|
233
|
+
- README.md
|
234
|
+
- Rakefile
|
235
|
+
- db/migrate/20180327044629_create_ruby_event_store_tables.rb
|
236
|
+
- lib/ruby_event_store-rom.rb
|
237
|
+
- lib/ruby_event_store/rom.rb
|
238
|
+
- lib/ruby_event_store/rom/adapters/sql/index_violation_detector.rb
|
239
|
+
- lib/ruby_event_store/rom/adapters/sql/rake_task.rb
|
240
|
+
- lib/ruby_event_store/rom/adapters/sql/relations/events.rb
|
241
|
+
- lib/ruby_event_store/rom/adapters/sql/relations/stream_entries.rb
|
242
|
+
- lib/ruby_event_store/rom/adapters/sql/tasks/migration_tasks.rake
|
243
|
+
- lib/ruby_event_store/rom/adapters/sql/unit_of_work.rb
|
244
|
+
- lib/ruby_event_store/rom/event_repository.rb
|
245
|
+
- lib/ruby_event_store/rom/mappers/event_to_serialized_record.rb
|
246
|
+
- lib/ruby_event_store/rom/mappers/stream_entry_to_serialized_record.rb
|
247
|
+
- lib/ruby_event_store/rom/repositories/events.rb
|
248
|
+
- lib/ruby_event_store/rom/repositories/stream_entries.rb
|
249
|
+
- lib/ruby_event_store/rom/sql.rb
|
250
|
+
- lib/ruby_event_store/rom/tuple_uniqueness_error.rb
|
251
|
+
- lib/ruby_event_store/rom/unit_of_work.rb
|
252
|
+
- lib/ruby_event_store/rom/version.rb
|
253
|
+
- ruby_event_store-rom.gemspec
|
254
|
+
homepage: https://railseventstore.org
|
255
|
+
licenses:
|
256
|
+
- MIT
|
257
|
+
metadata:
|
258
|
+
homepage_uri: https://railseventstore.org/
|
259
|
+
changelog_uri: https://github.com/RailsEventStore/rails_event_store/releases
|
260
|
+
source_code_uri: https://github.com/RailsEventStore/rails_event_store
|
261
|
+
bug_tracker_uri: https://github.com/RailsEventStore/rails_event_store/issues
|
262
|
+
post_install_message:
|
263
|
+
rdoc_options: []
|
264
|
+
require_paths:
|
265
|
+
- lib
|
266
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
267
|
+
requirements:
|
268
|
+
- - ">="
|
269
|
+
- !ruby/object:Gem::Version
|
270
|
+
version: '0'
|
271
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
272
|
+
requirements:
|
273
|
+
- - ">="
|
274
|
+
- !ruby/object:Gem::Version
|
275
|
+
version: '0'
|
276
|
+
requirements: []
|
277
|
+
rubyforge_project:
|
278
|
+
rubygems_version: 2.7.6
|
279
|
+
signing_key:
|
280
|
+
specification_version: 4
|
281
|
+
summary: ROM events repository for Ruby Event Store
|
282
|
+
test_files: []
|