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.
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