sandthorn_driver_sequel_2 0.0.1
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/.autotest +3 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +37 -0
- data/Rakefile +10 -0
- data/lib/sandthorn_driver_sequel_2/access/event_access.rb +94 -0
- data/lib/sandthorn_driver_sequel_2/access/snapshot_access.rb +88 -0
- data/lib/sandthorn_driver_sequel_2/access.rb +19 -0
- data/lib/sandthorn_driver_sequel_2/errors.rb +49 -0
- data/lib/sandthorn_driver_sequel_2/event_query.rb +68 -0
- data/lib/sandthorn_driver_sequel_2/event_store.rb +138 -0
- data/lib/sandthorn_driver_sequel_2/event_store_context.rb +15 -0
- data/lib/sandthorn_driver_sequel_2/file_output_wrappers/events.rb +37 -0
- data/lib/sandthorn_driver_sequel_2/migration.rb +81 -0
- data/lib/sandthorn_driver_sequel_2/sequel_driver.rb +23 -0
- data/lib/sandthorn_driver_sequel_2/storage.rb +43 -0
- data/lib/sandthorn_driver_sequel_2/utilities/array.rb +13 -0
- data/lib/sandthorn_driver_sequel_2/utilities.rb +1 -0
- data/lib/sandthorn_driver_sequel_2/version.rb +3 -0
- data/lib/sandthorn_driver_sequel_2/wrappers/event_wrapper.rb +12 -0
- data/lib/sandthorn_driver_sequel_2/wrappers/snapshot_wrapper.rb +11 -0
- data/lib/sandthorn_driver_sequel_2/wrappers.rb +2 -0
- data/lib/sandthorn_driver_sequel_2.rb +24 -0
- data/sandthorn_driver_sequel_2.gemspec +41 -0
- data/spec/asking_for_aggregates_to_snapshot_spec.rb +64 -0
- data/spec/benchmark_spec.rb +125 -0
- data/spec/db/.keep +0 -0
- data/spec/driver_interface_spec.rb +31 -0
- data/spec/event_access_spec.rb +100 -0
- data/spec/event_store_file_output_spec.rb +44 -0
- data/spec/event_store_with_context_spec.rb +25 -0
- data/spec/get_events_spec.rb +128 -0
- data/spec/migration_specifying_domain_spec.rb +32 -0
- data/spec/saving_events_spec.rb +90 -0
- data/spec/saving_snapshot_spec.rb +77 -0
- data/spec/snapshot_access_spec.rb +125 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/storage_spec.rb +66 -0
- data/spec/storage_to_file_spec.rb +53 -0
- metadata +334 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'sandthorn_driver_sequel_2/sequel_driver'
|
2
|
+
module SandthornDriverSequel2
|
3
|
+
class Migration
|
4
|
+
include EventStoreContext
|
5
|
+
attr_reader :driver, :context
|
6
|
+
def initialize url: nil, context: nil
|
7
|
+
@driver = SequelDriver.new url: url
|
8
|
+
@context = context
|
9
|
+
end
|
10
|
+
def migrate!
|
11
|
+
ensure_migration_table!
|
12
|
+
events
|
13
|
+
snapshots
|
14
|
+
end
|
15
|
+
private
|
16
|
+
def clear_for_test
|
17
|
+
driver.execute do |db|
|
18
|
+
db[snapshots_table_name].truncate
|
19
|
+
db[events_table_name].truncate
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def events
|
24
|
+
events_migration_0 = "#{events_table_name}-20130308"
|
25
|
+
unless has_been_migrated?(events_migration_0)
|
26
|
+
driver.execute_in_transaction do |db|
|
27
|
+
db.create_table(events_table_name) do
|
28
|
+
primary_key :sequence_number
|
29
|
+
String :aggregate_id, fixed: true, size: 36, null: false
|
30
|
+
Integer :aggregate_version, null: false
|
31
|
+
String :aggregate_type, size: 255, null: false
|
32
|
+
String :event_name, size: 255, null: false
|
33
|
+
String :event_data, text: true, null: true
|
34
|
+
DateTime :timestamp, null: false
|
35
|
+
|
36
|
+
index [:aggregate_type]
|
37
|
+
index [:event_name]
|
38
|
+
index [:aggregate_id]
|
39
|
+
index [:aggregate_id, :aggregate_version], unique: true
|
40
|
+
end
|
41
|
+
was_migrated events_migration_0, db
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
def snapshots
|
46
|
+
snapshot_migration_0 = "#{snapshots_table_name}-20130312"
|
47
|
+
unless has_been_migrated?(snapshot_migration_0)
|
48
|
+
driver.execute_in_transaction do |db|
|
49
|
+
db.create_table(snapshots_table_name) do
|
50
|
+
primary_key :id
|
51
|
+
Integer :aggregate_version, null: false
|
52
|
+
String :snapshot_data, text: true, null: false
|
53
|
+
String :aggregate_id, fixed: true, size: 36, null: false
|
54
|
+
index [:aggregate_id], unique: true
|
55
|
+
end
|
56
|
+
was_migrated snapshot_migration_0, db
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def migration_table_name
|
62
|
+
:event_store_sequel_migrations
|
63
|
+
end
|
64
|
+
def ensure_migration_table!
|
65
|
+
driver.execute do |db|
|
66
|
+
db.create_table?(migration_table_name) do
|
67
|
+
primary_key :id
|
68
|
+
String :migration_name, null: false
|
69
|
+
index [:migration_name], unique: true
|
70
|
+
DateTime :timestamp, :null=>false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
def has_been_migrated? migration_name
|
75
|
+
driver.execute {|db| db[migration_table_name].all.any? { |e| e[:migration_name]==migration_name } }
|
76
|
+
end
|
77
|
+
def was_migrated migration_name, db
|
78
|
+
db[migration_table_name].insert timestamp: Time.now.utc, migration_name: migration_name
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
|
3
|
+
module SandthornDriverSequel2
|
4
|
+
class SequelDriver
|
5
|
+
|
6
|
+
def initialize args = {}
|
7
|
+
@url = args.fetch(:url)
|
8
|
+
Sequel.default_timezone = :utc
|
9
|
+
@db = Sequel.connect(@url)
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute
|
13
|
+
yield @db
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute_in_transaction &block
|
17
|
+
@db.transaction do
|
18
|
+
block.call(@db)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module SandthornDriverSequel2
|
2
|
+
class Storage
|
3
|
+
# = Storage
|
4
|
+
# Abstracts access to contextualized database tables.
|
5
|
+
#
|
6
|
+
# == Rationale
|
7
|
+
# Provide object-oriented access to the different tables to other objects.
|
8
|
+
# Make it unnecessary for them to know about the current context.
|
9
|
+
include EventStoreContext
|
10
|
+
|
11
|
+
attr_reader :db
|
12
|
+
|
13
|
+
def initialize(db, context, events_file_path)
|
14
|
+
@db = db
|
15
|
+
@context = context
|
16
|
+
@event_file = File.open(events_file_path, "a") if events_file_path
|
17
|
+
last_event = events_table.order(:sequence_number).limit(1).last
|
18
|
+
last_sequence_number = last_event ? last_event[:sequence_number] : 0
|
19
|
+
@event_file_output_wrapper = FileOutputWrapper::Events.new @event_file, last_sequence_number if @event_file
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns a Sequel::Model for accessing events
|
23
|
+
def events
|
24
|
+
agg = Class.new(Sequel::Model(events_table))
|
25
|
+
return @event_file_output_wrapper.events agg if @event_file
|
26
|
+
agg
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns a Sequel::Model for accessing snapshots
|
30
|
+
def snapshots
|
31
|
+
Class.new(Sequel::Model(snapshots_table))
|
32
|
+
end
|
33
|
+
|
34
|
+
def events_table
|
35
|
+
db[events_table_name]
|
36
|
+
end
|
37
|
+
|
38
|
+
def snapshots_table
|
39
|
+
db[snapshots_table_name]
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "sandthorn_driver_sequel_2/utilities/array"
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
module SandthornDriverSequel2
|
3
|
+
class EventWrapper < SimpleDelegator
|
4
|
+
|
5
|
+
[:aggregate_version, :event_name, :event_data, :timestamp, :aggregate_id, :aggregate_type].each do |attribute|
|
6
|
+
define_method(attribute) do
|
7
|
+
fetch(attribute)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "sandthorn_driver_sequel_2/version"
|
2
|
+
require "sandthorn_driver_sequel_2/utilities"
|
3
|
+
require "sandthorn_driver_sequel_2/wrappers"
|
4
|
+
require "sandthorn_driver_sequel_2/event_query"
|
5
|
+
require "sandthorn_driver_sequel_2/event_store_context"
|
6
|
+
require "sandthorn_driver_sequel_2/access"
|
7
|
+
require "sandthorn_driver_sequel_2/storage"
|
8
|
+
require 'sandthorn_driver_sequel_2/event_store'
|
9
|
+
require 'sandthorn_driver_sequel_2/errors'
|
10
|
+
require 'sandthorn_driver_sequel_2/migration'
|
11
|
+
require 'sandthorn_driver_sequel_2/file_output_wrappers/events'
|
12
|
+
|
13
|
+
module SandthornDriverSequel2
|
14
|
+
class << self
|
15
|
+
def driver_from_url url: nil, context: nil, events_file_path: nil
|
16
|
+
EventStore.new url: url, context: context, events_file_path: events_file_path
|
17
|
+
end
|
18
|
+
def migrate_db url: nil, context: nil
|
19
|
+
migrator = Migration.new url: url, context: context
|
20
|
+
migrator.migrate!
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sandthorn_driver_sequel_2/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sandthorn_driver_sequel_2"
|
8
|
+
spec.version = SandthornDriverSequel2::VERSION
|
9
|
+
spec.authors = ["Lars Krantz", "Morgan Hallgren", "Jesper Josefsson"]
|
10
|
+
spec.email = ["lars.krantz@alaz.se", "morgan.hallgren@gmail.com", "jesper.josefsson@gmail.com"]
|
11
|
+
spec.description = %q{Sequel driver for Sandthorn}
|
12
|
+
spec.summary = %q{Sequel driver for Sandthorn that store all data to events table and makes it possible to dump instert to disk}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.required_ruby_version = ">= 2.0"
|
17
|
+
|
18
|
+
spec.files = `git ls-files`.split($/)
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
spec.add_development_dependency "gem-release"
|
28
|
+
spec.add_development_dependency "sqlite3"
|
29
|
+
spec.add_development_dependency "pry"
|
30
|
+
spec.add_development_dependency "pry-doc"
|
31
|
+
spec.add_development_dependency "awesome_print"
|
32
|
+
spec.add_development_dependency "autotest-standalone"
|
33
|
+
spec.add_development_dependency "uuidtools"
|
34
|
+
spec.add_development_dependency "ruby-beautify"
|
35
|
+
spec.add_development_dependency "msgpack"
|
36
|
+
spec.add_development_dependency "snappy"
|
37
|
+
spec.add_development_dependency "guard-rspec"
|
38
|
+
|
39
|
+
spec.add_runtime_dependency "sequel", "~> 4.17"
|
40
|
+
spec.add_runtime_dependency "pg"
|
41
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# require 'spec_helper'
|
2
|
+
|
3
|
+
# class Foo; end
|
4
|
+
# class Bar; end
|
5
|
+
|
6
|
+
# module SandthornDriverSequel2
|
7
|
+
|
8
|
+
# describe EventStore do
|
9
|
+
# before(:each) { prepare_for_test }
|
10
|
+
# context "when asking for aggregates to snapshot" do
|
11
|
+
# let(:aggregates) {
|
12
|
+
# [{id: "1", class_name: Foo}, {id: "2", class_name: Bar},{id: "3", class_name: Foo}]}
|
13
|
+
|
14
|
+
# before(:each) {save_test_events}
|
15
|
+
|
16
|
+
# context "when asking for type 'Bar' and max event count 5" do
|
17
|
+
# let(:needs_snapshot) { event_store.obsolete_snapshots aggregate_types: [Bar], max_event_distance: 5 }
|
18
|
+
# context "and no snapshots exist" do
|
19
|
+
# it "should return that id 2 with class Bar need to be snapshotted" do
|
20
|
+
# expect(needs_snapshot.length).to eql 1
|
21
|
+
# expect(needs_snapshot.first[:aggregate_id]).to eql aggregates[1][:id]
|
22
|
+
# expect(needs_snapshot.first[:aggregate_type]).to eql "Bar"
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
# context "and a recent snapshot exists" do
|
26
|
+
# before(:each) do
|
27
|
+
# snapshot_data = { event_data: "YO MAN", aggregate_version: 11 }
|
28
|
+
# event_store.save_snapshot(snapshot_data, aggregates[1][:id])
|
29
|
+
# end
|
30
|
+
# it "should return nil" do
|
31
|
+
# expect(needs_snapshot).to be_empty
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
|
36
|
+
|
37
|
+
# def save_test_events
|
38
|
+
# for_1 = event_generator count: 4, start_at: 1
|
39
|
+
# for_2 = event_generator count: 3, start_at: 1
|
40
|
+
# for_3 = event_generator count: 6, start_at: 1
|
41
|
+
# for_2_2 = event_generator count: 10, start_at: 4
|
42
|
+
# for_1_2 = event_generator count: 1, start_at: 5
|
43
|
+
# save_events for_1, 0
|
44
|
+
# save_events for_2, 1
|
45
|
+
# save_events for_3, 2
|
46
|
+
# save_events for_1_2, 0
|
47
|
+
# save_events for_2_2, 1
|
48
|
+
# end
|
49
|
+
# def save_events events, aggregate_index
|
50
|
+
# event_store.save_events events, aggregates[aggregate_index][:id], aggregates[aggregate_index][:class_name]
|
51
|
+
# end
|
52
|
+
|
53
|
+
# def event_generator count: 1, start_at: 1
|
54
|
+
# events = []
|
55
|
+
# i = 0
|
56
|
+
# while i < count do
|
57
|
+
# events << { aggregate_version: i+start_at, event_data: nil, event_name: "event_foo_#{i}" }
|
58
|
+
# i += 1
|
59
|
+
# end
|
60
|
+
# events
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'benchmark'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Sandthorn
|
6
|
+
module AggregateRoot
|
7
|
+
|
8
|
+
describe "benchmark", benchmark: true do
|
9
|
+
|
10
|
+
before(:each) { prepare_for_test }
|
11
|
+
let(:test_events_20_events) do
|
12
|
+
e = []
|
13
|
+
e << {aggregate_version: 1, event_name: "new", event_data: "---\n:method_name: new\n:method_args: []\n:attribute_deltas:\n- :attribute_name: :@aggregate_id\n :old_value: \n :new_value: 0a74e545-be84-4506-8b0a-73e947856327\n"}
|
14
|
+
19.times do |i|
|
15
|
+
e << {aggregate_version: i+2, event_name: "foo", event_data: "A2"}
|
16
|
+
end
|
17
|
+
e
|
18
|
+
end
|
19
|
+
let(:test_events_one_event) do
|
20
|
+
e = []
|
21
|
+
e << {aggregate_version: 1, event_name: "new", event_data: "B1" }
|
22
|
+
end
|
23
|
+
let(:test_events_two_events) do
|
24
|
+
e = []
|
25
|
+
e << {aggregate_version: 1, event_name: "new", event_data: "---\n:method_name: new\n:method_args: []\n:attribute_deltas:\n- :attribute_name: :@aggregate_id\n :old_value: \n :new_value: 0a74e545-be84-4506-8b0a-73e947856327\n"}
|
26
|
+
e << {aggregate_version: 2, event_name: "foo", event_data: "A2"}
|
27
|
+
end
|
28
|
+
let(:aggregate_id) {"c0456e26-2345-4f67-92fa-130b3a31a39a"}
|
29
|
+
let(:es) { event_store }
|
30
|
+
|
31
|
+
|
32
|
+
n = 500
|
33
|
+
describe "save" do
|
34
|
+
it "one event save 500 times" do
|
35
|
+
Benchmark.bm do |x|
|
36
|
+
x.report("new change save find") { for i in 1..n; es.save_events(test_events_one_event, 0, i.to_s, SandthornDriverSequel2::EventStore); end }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
it "two events save 500 times" do
|
40
|
+
Benchmark.bm do |x|
|
41
|
+
x.report("new change save find") { for i in 1..n; es.save_events(test_events_two_events, 0, i.to_s, SandthornDriverSequel2::EventStore); end }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
it "twenty events save 500 times" do
|
45
|
+
Benchmark.bm do |x|
|
46
|
+
x.report("new change save find") { for i in 1..n; es.save_events(test_events_20_events, 0, i.to_s, SandthornDriverSequel2::EventStore); end }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "find" do
|
52
|
+
it "should find one event 500 times" do
|
53
|
+
es.save_events(test_events_one_event, 0, aggregate_id, SandthornDriverSequel2::EventStore)
|
54
|
+
|
55
|
+
Benchmark.bm do |x|
|
56
|
+
x.report("find") { for i in 1..n; es.get_aggregate(aggregate_id, SandthornDriverSequel2::EventStore); end }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
it "should find two events 500 times" do
|
60
|
+
es.save_events(test_events_two_events, 0, aggregate_id, SandthornDriverSequel2::EventStore)
|
61
|
+
|
62
|
+
Benchmark.bm do |x|
|
63
|
+
x.report("find") { for i in 1..n; es.get_aggregate(aggregate_id, SandthornDriverSequel2::EventStore); end }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
it "should find twenty events 500 times" do
|
67
|
+
es.save_events(test_events_20_events, 0, aggregate_id, SandthornDriverSequel2::EventStore)
|
68
|
+
|
69
|
+
Benchmark.bm do |x|
|
70
|
+
x.report("find") { for i in 1..n; es.get_aggregate(aggregate_id, SandthornDriverSequel2::EventStore); end }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
describe "find with snapshot" do
|
76
|
+
|
77
|
+
it "should find one event that is snapshoted 500 times" do
|
78
|
+
snapshot_data = { event_data: YAML.dump(Object.new), aggregate_version: 1 }
|
79
|
+
es.save_events(test_events_one_event, 0, aggregate_id, SandthornDriverSequel2::EventStore)
|
80
|
+
es.save_snapshot(snapshot_data, aggregate_id, SandthornDriverSequel2::EventStore)
|
81
|
+
|
82
|
+
Benchmark.bm do |x|
|
83
|
+
x.report("find") { for i in 1..n; es.get_aggregate(aggregate_id, SandthornDriverSequel2::EventStore); end }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
it "should find two events that is snapshoted 500 times" do
|
87
|
+
snapshot_data = { event_data: YAML.dump(Object.new), aggregate_version: 2 }
|
88
|
+
es.save_events(test_events_two_events, 0, aggregate_id, SandthornDriverSequel2::EventStore)
|
89
|
+
es.save_snapshot(snapshot_data, aggregate_id, SandthornDriverSequel2::EventStore)
|
90
|
+
Benchmark.bm do |x|
|
91
|
+
x.report("find") { for i in 1..n; es.get_aggregate(aggregate_id, SandthornDriverSequel2::EventStore); end }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
it "should find twenty events that is snapshoted 500 times" do
|
95
|
+
snapshot_data = { event_data: YAML.dump(Object.new), aggregate_version: 19 }
|
96
|
+
es.save_events(test_events_20_events, 0, aggregate_id, SandthornDriverSequel2::EventStore)
|
97
|
+
es.save_snapshot(snapshot_data, aggregate_id, SandthornDriverSequel2::EventStore)
|
98
|
+
|
99
|
+
Benchmark.bm do |x|
|
100
|
+
x.report("find") { for i in 1..n; es.get_aggregate(aggregate_id, SandthornDriverSequel2::EventStore); end }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
# it "new save and find 500 aggregates" do
|
106
|
+
|
107
|
+
# Benchmark.bm do |x|
|
108
|
+
# x.report("new change save find") { for i in 1..n; es.save_events(test_events_a, 0, i.to_s, SandthornDriverSequel2::EventStore); es.get_aggregate(i.to_s, SandthornDriverSequel2::EventStore); end }
|
109
|
+
# end
|
110
|
+
|
111
|
+
# end
|
112
|
+
|
113
|
+
# it "should commit 500 actions" do
|
114
|
+
# Benchmark.bm do |x|
|
115
|
+
# x.report("commit") { for i in 1..n; test_object.change_name "#{i}"; end }
|
116
|
+
# end
|
117
|
+
# end
|
118
|
+
# it "should commit and save 500 actions" do
|
119
|
+
# Benchmark.bm do |x|
|
120
|
+
# x.report("commit save") { for i in 1..n; test_object.change_name("#{i}").save; end }
|
121
|
+
# end
|
122
|
+
# end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/spec/db/.keep
ADDED
File without changes
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module SandthornDriverSequel2
|
4
|
+
describe EventStore do
|
5
|
+
before(:each) { prepare_for_test }
|
6
|
+
context "interface structure" do
|
7
|
+
let(:subject) { event_store }
|
8
|
+
methods = [
|
9
|
+
:save_events,
|
10
|
+
:save_snapshot,
|
11
|
+
:get_aggregate_events_from_snapshot,
|
12
|
+
:get_aggregate,
|
13
|
+
:get_aggregate_events,
|
14
|
+
:get_aggregate_ids,
|
15
|
+
# :get_all_types,
|
16
|
+
:get_snapshot,
|
17
|
+
:get_events,
|
18
|
+
:url,
|
19
|
+
:context,
|
20
|
+
:driver
|
21
|
+
]
|
22
|
+
|
23
|
+
methods.each do |method|
|
24
|
+
it "responds to #{method}" do
|
25
|
+
expect(subject).to respond_to(method)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module SandthornDriverSequel2
|
4
|
+
describe EventAccess do
|
5
|
+
include EventStoreContext
|
6
|
+
|
7
|
+
before do
|
8
|
+
prepare_for_test
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:context) { :test }
|
12
|
+
let(:db) { Sequel.connect(event_store_url)}
|
13
|
+
let(:aggregate_id) { SecureRandom.uuid }
|
14
|
+
let(:aggregate) do
|
15
|
+
aggregate_access.register_aggregate(aggregate_id, "foo")
|
16
|
+
end
|
17
|
+
let(:storage) { Storage.new(db, :test, nil) }
|
18
|
+
let(:aggregate_access) { AggregateAccess.new(storage) }
|
19
|
+
let(:snapshot_access) { SnapshotAccess.new(storage)}
|
20
|
+
let(:access) { EventAccess.new(storage) }
|
21
|
+
|
22
|
+
let(:events) do
|
23
|
+
[
|
24
|
+
{
|
25
|
+
aggregate_version: 1,
|
26
|
+
aggregate_id: aggregate_id,
|
27
|
+
aggregate_type: "Foo",
|
28
|
+
event_name: "new",
|
29
|
+
event_data: "new_data"
|
30
|
+
},{
|
31
|
+
aggregate_version: 2,
|
32
|
+
aggregate_id: aggregate_id,
|
33
|
+
aggregate_type: "Foo",
|
34
|
+
event_name: "foo",
|
35
|
+
event_data: "foo_data"
|
36
|
+
}
|
37
|
+
]
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#store_events" do
|
41
|
+
|
42
|
+
it "handles both arrays and single events" do
|
43
|
+
access.store_events(events[0])
|
44
|
+
events = access.find_events_by_aggregate_id(aggregate_id)
|
45
|
+
expect(events.length).to eq(1)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "adds timestamps to all events and associates them to the aggregate" do
|
49
|
+
access.store_events(events)
|
50
|
+
events = access.find_events_by_aggregate_id(aggregate_id)
|
51
|
+
expect(events.map(&:timestamp).all?).to be_truthy
|
52
|
+
end
|
53
|
+
|
54
|
+
# it "updates the aggregate version" do
|
55
|
+
# access.store_events(events)
|
56
|
+
# events = access.find_events_by_aggregate_id(aggregate_id)
|
57
|
+
# version = events.map(&:aggregate_version).max
|
58
|
+
|
59
|
+
# reloaded_aggregate = aggregate_access.find(aggregate.id)
|
60
|
+
# expect(reloaded_aggregate.aggregate_version).to eq(version)
|
61
|
+
# end
|
62
|
+
|
63
|
+
context "when the aggregate version of an event is incorrect" do
|
64
|
+
it "throws an error" do
|
65
|
+
event = { aggregate_version: 100, aggregate_id: aggregate_id, aggregate_type: "Foo", event_name: "new", event_data: "noop" }
|
66
|
+
expect { access.store_events([event])}.not_to raise_error
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#find_events_by_aggregate_id" do
|
72
|
+
context "when there are events" do
|
73
|
+
it "returns correct events" do
|
74
|
+
access.store_events(events)
|
75
|
+
|
76
|
+
stored_events = access.find_events_by_aggregate_id(aggregate_id)
|
77
|
+
expect(stored_events.map(&:aggregate_id)).to all(eq(aggregate_id))
|
78
|
+
expect(stored_events.size).to eq(events.size)
|
79
|
+
expect(stored_events).to all(respond_to(:merge))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#after_snapshot" do
|
85
|
+
it "returns events after the given snapshot" do
|
86
|
+
access.store_events(events.first)
|
87
|
+
|
88
|
+
snapshot_id = snapshot_access.record_snapshot(aggregate_id, { aggregate_version: 1, event_data: "foo"})
|
89
|
+
snapshot = snapshot_access.find(snapshot_id)
|
90
|
+
|
91
|
+
access.store_events(events.last)
|
92
|
+
|
93
|
+
events = access.after_snapshot(snapshot)
|
94
|
+
expect(events.count).to eq(1)
|
95
|
+
expect(events.first[:event_data]).to eq("foo_data")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module SandthornDriverSequel2
|
3
|
+
describe EventStore do
|
4
|
+
before(:each) { prepare_for_test context: nil; }
|
5
|
+
#after(:each) {File.delete(aggregates_file); File.delete(events_file);}
|
6
|
+
let(:events_file) {"spec/db_file/test_events.csv"}
|
7
|
+
let(:aggregates_file) {"spec/db_file/test_aggregates.csv"}
|
8
|
+
let(:event_store_file_output) { EventStore.new url: event_store_url, events_file_path: events_file }
|
9
|
+
|
10
|
+
let(:test_events) do
|
11
|
+
e = []
|
12
|
+
e << {aggregate_version: 1, event_name: "new", event_args: nil, event_data: "---\n:method_name: new\n:method_args: []\n:attribute_deltas:\n- :attribute_name: :@aggregate_id\n :old_value: \n :new_value: 0a74e545-be84-4506-8b0a-73e947856327\n"}
|
13
|
+
e << {aggregate_version: 2, event_name: "foo", event_args: ["bar"], event_data: "noop"}
|
14
|
+
e << {aggregate_version: 3, event_name: "flubber", event_args: ["bar"] , event_data: "noop"}
|
15
|
+
end
|
16
|
+
let(:aggregate_id) {"c0456e26-e29a-4f67-92fa-130b3a31a39b"}
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
context("when saving to a event_store that store its data to file") do
|
21
|
+
|
22
|
+
before(:each) { event_store_file_output.save_events test_events, aggregate_id, String }
|
23
|
+
|
24
|
+
it "should store but not find" do
|
25
|
+
event_store_file_output.save_events test_events, aggregate_id, String
|
26
|
+
expect(event_store_file_output.get_aggregate_events(aggregate_id)).to eq([])
|
27
|
+
end
|
28
|
+
# it "should output one line to aggregates file" do
|
29
|
+
# event_store_file_output.save_events test_events, aggregate_id, String
|
30
|
+
|
31
|
+
# fd = File.open aggregates_file
|
32
|
+
|
33
|
+
# l = 0
|
34
|
+
# puts "!!!!!"
|
35
|
+
# fd.each do |line|
|
36
|
+
# l += 1
|
37
|
+
# puts "HERE!!! #{line}"
|
38
|
+
# end
|
39
|
+
# expect(l).to eql 1
|
40
|
+
|
41
|
+
# end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module SandthornDriverSequel2
|
3
|
+
describe EventStore do
|
4
|
+
let(:context) { :event_store_spec }
|
5
|
+
before(:each) { prepare_for_test context: context; prepare_for_test context: nil; }
|
6
|
+
let(:event_store_with_context) { EventStore.new url: event_store_url, context: context }
|
7
|
+
let(:event_store_without_context) { EventStore.new url: event_store_url }
|
8
|
+
context("when saving in one context and retrieving in another") do
|
9
|
+
let(:test_events) do
|
10
|
+
e = []
|
11
|
+
e << {aggregate_version: 1, event_name: "new", event_args: nil, event_data: "---\n:method_name: new\n:method_args: []\n:attribute_deltas:\n- :attribute_name: :@aggregate_id\n :old_value: \n :new_value: 0a74e545-be84-4506-8b0a-73e947856327\n"}
|
12
|
+
e << {aggregate_version: 2, event_name: "foo", event_args: ["bar"], event_data: "noop"}
|
13
|
+
e << {aggregate_version: 3, event_name: "flubber", event_args: ["bar"] , event_data: "noop"}
|
14
|
+
end
|
15
|
+
let(:aggregate_id) {"c0456e26-e29a-4f67-92fa-130b3a31a39b"}
|
16
|
+
it "should not find them" do
|
17
|
+
event_store_without_context.save_events test_events, aggregate_id, String
|
18
|
+
events = event_store_without_context.get_aggregate_events aggregate_id
|
19
|
+
expect(events.length).to eql test_events.length
|
20
|
+
events_2 = event_store_with_context.get_aggregate_events aggregate_id
|
21
|
+
expect(events_2.length).to eql 0
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|