eventus 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,6 +16,18 @@ module Eventus
16
16
  def persistence
17
17
  @persistence ||= Eventus.persistence
18
18
  end
19
+
20
+ def conflicts(added = {})
21
+ @event_conflicts ||= {}
22
+ added.each do |k,v|
23
+ @event_conflicts[k.to_s] = v.respond_to?(:map) ? v.map{|e| e.to_s} : v.to_s
24
+ end
25
+ end
26
+
27
+ def conflict?(e1, e2)
28
+ return false unless @event_conflicts
29
+ @event_conflicts.fetch(e1,[]).include?(e2) || @event_conflicts.fetch(e2,[]).include?(e1)
30
+ end
19
31
  end
20
32
 
21
33
  module InstanceMethods
@@ -27,7 +39,15 @@ module Eventus
27
39
  end
28
40
 
29
41
  def save
42
+ version = @stream.version
30
43
  @stream.commit
44
+ true
45
+ rescue Eventus::ConcurrencyError
46
+ committed = @stream.committed_events[version-1..-1]
47
+ uncommitted = @stream.uncommitted_events
48
+ conflict = committed.any?{ |e| uncommitted.any? {|u| self.class.conflict?(e['name'], u['name'])} }
49
+ raise Eventus::ConflictError if conflict
50
+ false
31
51
  end
32
52
 
33
53
  protected
@@ -1,4 +1,5 @@
1
1
  module Eventus
2
2
  class ConcurrencyError < ::StandardError; end
3
+ class ConflictError < ::StandardError; end
3
4
  class ConnectionError < ::StandardError; end
4
5
  end
@@ -1,3 +1,3 @@
1
1
  module Eventus
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.2"
3
3
  end
@@ -5,6 +5,8 @@ class TestAgg
5
5
 
6
6
  attr_accessor :loaded
7
7
 
8
+ conflicts :cake_baked => :cake_baked
9
+
8
10
  def bake_cake
9
11
  apply_change :cake_baked, :flavor => 'strawberry'
10
12
  end
@@ -55,15 +57,29 @@ describe Eventus::AggregateRoot do
55
57
 
56
58
  describe "when saving" do
57
59
  let(:aggregate) { TestAgg.new }
58
- let(:stream) { stub(:stream, :committed_events => []) }
60
+ let(:stream) { stub(:stream, :committed_events => events, :version => events.length) }
61
+ let(:events) { [{'name' => 'cake_baked'}] }
59
62
 
60
63
  before do
61
64
  aggregate.populate(stream)
62
65
  end
63
66
 
64
- it "should commit stream" do
67
+ it "should return true when no concurrency error" do
65
68
  stream.should_receive(:commit)
66
- aggregate.save
69
+ aggregate.save.should == true
70
+ end
71
+
72
+ it "should return false if no conflict" do
73
+ stream.should_receive(:commit).and_raise(Eventus::ConcurrencyError)
74
+ stream.should_receive(:uncommitted_events).and_return([{'name' => 'coconut'}])
75
+
76
+ aggregate.save.should == false
77
+ end
78
+
79
+ it "should raise conflict error if conflict exists" do
80
+ stream.should_receive(:commit).and_raise(Eventus::ConcurrencyError)
81
+ stream.should_receive(:uncommitted_events).and_return([{'name' => 'cake_baked'}])
82
+ lambda {aggregate.save}.should raise_error(Eventus::ConflictError)
67
83
  end
68
84
  end
69
85
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eventus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-16 00:00:00.000000000Z
12
+ date: 2012-01-17 00:00:00.000000000Z
13
13
  dependencies: []
14
14
  description: An Event Store
15
15
  email:
@@ -57,7 +57,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
57
57
  version: '0'
58
58
  segments:
59
59
  - 0
60
- hash: 2674942126495806471
60
+ hash: 24983203454212459
61
61
  required_rubygems_version: !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
@@ -66,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
66
66
  version: '0'
67
67
  segments:
68
68
  - 0
69
- hash: 2674942126495806471
69
+ hash: 24983203454212459
70
70
  requirements: []
71
71
  rubyforge_project: eventus
72
72
  rubygems_version: 1.8.13