sandthorn_driver_sequel_2 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|