sandthorn_driver_sequel_2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +3 -0
  3. data/.gitignore +20 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +4 -0
  8. data/Gemfile +4 -0
  9. data/Guardfile +7 -0
  10. data/LICENSE.txt +22 -0
  11. data/README.md +37 -0
  12. data/Rakefile +10 -0
  13. data/lib/sandthorn_driver_sequel_2/access/event_access.rb +94 -0
  14. data/lib/sandthorn_driver_sequel_2/access/snapshot_access.rb +88 -0
  15. data/lib/sandthorn_driver_sequel_2/access.rb +19 -0
  16. data/lib/sandthorn_driver_sequel_2/errors.rb +49 -0
  17. data/lib/sandthorn_driver_sequel_2/event_query.rb +68 -0
  18. data/lib/sandthorn_driver_sequel_2/event_store.rb +138 -0
  19. data/lib/sandthorn_driver_sequel_2/event_store_context.rb +15 -0
  20. data/lib/sandthorn_driver_sequel_2/file_output_wrappers/events.rb +37 -0
  21. data/lib/sandthorn_driver_sequel_2/migration.rb +81 -0
  22. data/lib/sandthorn_driver_sequel_2/sequel_driver.rb +23 -0
  23. data/lib/sandthorn_driver_sequel_2/storage.rb +43 -0
  24. data/lib/sandthorn_driver_sequel_2/utilities/array.rb +13 -0
  25. data/lib/sandthorn_driver_sequel_2/utilities.rb +1 -0
  26. data/lib/sandthorn_driver_sequel_2/version.rb +3 -0
  27. data/lib/sandthorn_driver_sequel_2/wrappers/event_wrapper.rb +12 -0
  28. data/lib/sandthorn_driver_sequel_2/wrappers/snapshot_wrapper.rb +11 -0
  29. data/lib/sandthorn_driver_sequel_2/wrappers.rb +2 -0
  30. data/lib/sandthorn_driver_sequel_2.rb +24 -0
  31. data/sandthorn_driver_sequel_2.gemspec +41 -0
  32. data/spec/asking_for_aggregates_to_snapshot_spec.rb +64 -0
  33. data/spec/benchmark_spec.rb +125 -0
  34. data/spec/db/.keep +0 -0
  35. data/spec/driver_interface_spec.rb +31 -0
  36. data/spec/event_access_spec.rb +100 -0
  37. data/spec/event_store_file_output_spec.rb +44 -0
  38. data/spec/event_store_with_context_spec.rb +25 -0
  39. data/spec/get_events_spec.rb +128 -0
  40. data/spec/migration_specifying_domain_spec.rb +32 -0
  41. data/spec/saving_events_spec.rb +90 -0
  42. data/spec/saving_snapshot_spec.rb +77 -0
  43. data/spec/snapshot_access_spec.rb +125 -0
  44. data/spec/spec_helper.rb +31 -0
  45. data/spec/storage_spec.rb +66 -0
  46. data/spec/storage_to_file_spec.rb +53 -0
  47. 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,13 @@
1
+ module SandthornDriverSequel2
2
+ module Utilities
3
+ def self.array_wrap(object)
4
+ if object.nil?
5
+ []
6
+ elsif object.respond_to?(:to_ary)
7
+ object.to_ary || [object]
8
+ else
9
+ [object]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1 @@
1
+ require "sandthorn_driver_sequel_2/utilities/array"
@@ -0,0 +1,3 @@
1
+ module SandthornDriverSequel2
2
+ VERSION = "0.0.1"
3
+ end
@@ -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,11 @@
1
+ module SandthornDriverSequel2
2
+ class SnapshotWrapper < SimpleDelegator
3
+ def aggregate_version
4
+ self[:aggregate_version]
5
+ end
6
+
7
+ def data
8
+ self[:event_data]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ require "sandthorn_driver_sequel_2/wrappers/event_wrapper"
2
+ require "sandthorn_driver_sequel_2/wrappers/snapshot_wrapper"
@@ -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