eventus 0.3.5 → 0.3.6

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.
data/Gemfile CHANGED
@@ -8,4 +8,5 @@ group :development do
8
8
  gem 'libnotify' if RUBY_PLATFORM =~ /linux/i
9
9
  gem 'uuid'
10
10
  gem 'kyotocabinet-ruby'
11
+ gem 'mongo'
11
12
  end
data/Rakefile CHANGED
@@ -1,4 +1 @@
1
1
  require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new
@@ -0,0 +1,76 @@
1
+ require 'mongo'
2
+
3
+ module Eventus
4
+ module Persistence
5
+ class Mongo
6
+ attr_reader :db
7
+
8
+ def initialize(uri, options={})
9
+ collection_name = options.delete(:collection) || 'eventus_commits'
10
+ @db = build_db(uri, options)
11
+ @commits = db.collection(collection_name)
12
+ end
13
+
14
+ def commit(events)
15
+ seqs = events.map{|e| e['sequence']}
16
+ doc = {
17
+ _id: "#{events[0]['sid']}_#{seqs.min}",
18
+ sid: events[0]['sid'],
19
+ min: seqs.min,
20
+ max: seqs.max,
21
+ events: events,
22
+ dispatched: false
23
+ }
24
+
25
+ future = @commits.find_one({sid:doc[:sid], max:{:$gte => doc[:min]}})
26
+ raise Eventus::ConcurrencyError if future
27
+ begin
28
+ @commits.insert(doc, safe:true)
29
+ rescue ::Mongo::OperationFailure => e
30
+ raise Eventus::ConcurrencyError if e.error_code == 11000
31
+ end
32
+ end
33
+
34
+ def load(id, min = nil)
35
+ Eventus.logger.debug "Loading stream: #{id}"
36
+ query = {sid:id}
37
+
38
+ if min
39
+ query[:max] = {:$gte => min}
40
+ end
41
+
42
+ min ||= 0
43
+
44
+ @commits.find(query).to_a
45
+ .map{|c| c['events']}
46
+ .flatten
47
+ .reject{|e| e['sequence'] < min}
48
+ .sort_by{|e| e['sequence']}
49
+ end
50
+
51
+ def load_undispatched
52
+ commits = @commits.find(dispatched: false).to_a
53
+ if commits.length > 0
54
+ Eventus.logger.info "#{commits.length} undispatched commits loaded"
55
+ end
56
+ commits
57
+ end
58
+
59
+ def mark_dispatched(commit_id)
60
+ Eventus.logger.debug "Marking #{commit_id} dispatched"
61
+ @commits.update({_id: commit_id}, {dispatched: true})
62
+ end
63
+
64
+ private
65
+
66
+ def build_db(uri, options={})
67
+ parts = URI.parse(uri)
68
+ raise "scheme must be mongodb, found #{parts.scheme}" unless parts.scheme == 'mongodb'
69
+ db = ::Mongo::Connection.new(parts.host, parts.port, options).db(parts.path.gsub(/^\//, ''))
70
+ db.authenticate(parts.user, parts.password) if parts.user && parts.password
71
+ db
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -1,6 +1,7 @@
1
1
  module Eventus
2
2
  module Persistence
3
3
  autoload :KyotoCabinet, 'eventus/persistence/kyotocabinet'
4
+ autoload :Mongo, 'eventus/persistence/mongo'
4
5
  autoload :InMemory, 'eventus/persistence/in_memory'
5
6
  end
6
7
  end
@@ -1,3 +1,3 @@
1
1
  module Eventus
2
- VERSION = "0.3.5"
2
+ VERSION = "0.3.6"
3
3
  end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eventus::Persistence::Mongo do
4
+ let(:persistence) { @persistence }
5
+ let(:uuid) { UUID.new }
6
+
7
+ before(:all) do
8
+ @persistence = Eventus::Persistence::Mongo.new('mongodb://localhost/test')
9
+ @persistence.db.collection('eventus_commits').drop
10
+ end
11
+
12
+ it "should store complex objects" do
13
+ id = uuid.generate :compact
14
+ o = {'a' => 'super', 'complex' => ['object', 'with', {'nested' => ['members', 'galore', 1]}]}
15
+ commit = create_commit(id, 1, o)
16
+ persistence.commit(commit)
17
+
18
+ result = persistence.load id
19
+ result[0].should == commit[0]
20
+ end
21
+
22
+ it "should return no events when key not found" do
23
+ result = persistence.load "my_id"
24
+ result.should be_empty
25
+ end
26
+
27
+ it "should return events ordered" do
28
+ id = uuid.generate :compact
29
+ persistence.commit create_commit(id, 1, "one", "two")
30
+ persistence.commit create_commit(id, 3, "three", "four")
31
+ persistence.commit create_commit(id, 5, "five", "six")
32
+ persistence.commit create_commit(uuid.generate, 1, "cake", "batter")
33
+
34
+ result = persistence.load id
35
+ result.map{|r| r['body']}.should == ["one", "two", "three", "four", "five", "six"]
36
+ end
37
+
38
+ describe "when events exist" do
39
+ let(:id) { uuid.generate :compact }
40
+ let(:events) { create_commit(id, 1, *(1..5)) }
41
+ before do
42
+ persistence.commit events
43
+ other_events = create_commit(uuid.generate(:compact), 1, (1..10))
44
+ persistence.commit other_events
45
+ end
46
+
47
+ it "should load events" do
48
+ result = persistence.load id
49
+ result.length.should == events.length
50
+ end
51
+
52
+ it "should load undispatched events" do
53
+ result = persistence.load_undispatched
54
+ end
55
+
56
+ it "should mark an event as dispatched" do
57
+ result = persistence.load_undispatched[0]
58
+ persistence.mark_dispatched(result['_id'])
59
+ persistence.load_undispatched.any?{|c| c['_id'] == result['_id']}.should be_false
60
+ end
61
+
62
+ it "should throw concurrency exception if the same event number is added" do
63
+ lambda {persistence.commit create_commit(id, 1, "This is taken")}.should raise_error(Eventus::ConcurrencyError)
64
+ lambda {persistence.commit create_commit(id, 2, "This is taken")}.should raise_error(Eventus::ConcurrencyError)
65
+ end
66
+
67
+ it "should rollback changes on concurrency error" do
68
+ lambda {persistence.commit create_commit(id, 1, "first", "second", "third")}.should raise_error(Eventus::ConcurrencyError)
69
+
70
+ result = persistence.load id
71
+ result.should == events
72
+ end
73
+
74
+ it "should load all events from a minimum" do
75
+ result = persistence.load id, 3
76
+ result.should == events.select {|e| e['sequence'] >= 3}
77
+ end
78
+ end
79
+
80
+ describe "when serialization is set" do
81
+ let(:serializer) { stub }
82
+ let(:persistence) { Eventus::Persistence::KyotoCabinet.new(:path => '%', :serializer => serializer) }
83
+
84
+ it "should use serializer" do
85
+ input = {:name => 'event'}
86
+ ser = "serialized!!"
87
+ id = uuid.generate :compact
88
+ commit = create_commit(id, 1, input)
89
+
90
+ serializer.should_receive(:serialize).with(commit[0]).and_return(ser)
91
+ serializer.should_receive(:deserialize).with(ser).and_return(input)
92
+
93
+
94
+ persistence.commit commit
95
+ result = persistence.load id
96
+ result[0].should == input
97
+ end
98
+ end
99
+ end
100
+
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.5
4
+ version: 0.3.6
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-18 00:00:00.000000000Z
12
+ date: 2012-02-22 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: An Event Store
15
15
  email:
@@ -32,6 +32,7 @@ files:
32
32
  - lib/eventus/persistence.rb
33
33
  - lib/eventus/persistence/in_memory.rb
34
34
  - lib/eventus/persistence/kyotocabinet.rb
35
+ - lib/eventus/persistence/mongo.rb
35
36
  - lib/eventus/serializers.rb
36
37
  - lib/eventus/serializers/marshal.rb
37
38
  - lib/eventus/serializers/msgpack.rb
@@ -41,6 +42,7 @@ files:
41
42
  - spec/dispatchers/synchronous_spec.rb
42
43
  - spec/persistence/in_memory_spec.rb
43
44
  - spec/persistence/kyotocabinet_spec.rb
45
+ - spec/persistence/mongo_spec.rb
44
46
  - spec/spec_helper.rb
45
47
  - spec/stream_spec.rb
46
48
  homepage: ''
@@ -55,21 +57,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
55
57
  - - ! '>='
56
58
  - !ruby/object:Gem::Version
57
59
  version: '0'
58
- segments:
59
- - 0
60
- hash: -247495815524544458
61
60
  required_rubygems_version: !ruby/object:Gem::Requirement
62
61
  none: false
63
62
  requirements:
64
63
  - - ! '>='
65
64
  - !ruby/object:Gem::Version
66
65
  version: '0'
67
- segments:
68
- - 0
69
- hash: -247495815524544458
70
66
  requirements: []
71
67
  rubyforge_project: eventus
72
- rubygems_version: 1.8.13
68
+ rubygems_version: 1.8.15
73
69
  signing_key:
74
70
  specification_version: 3
75
71
  summary: Event Store
@@ -78,5 +74,6 @@ test_files:
78
74
  - spec/dispatchers/synchronous_spec.rb
79
75
  - spec/persistence/in_memory_spec.rb
80
76
  - spec/persistence/kyotocabinet_spec.rb
77
+ - spec/persistence/mongo_spec.rb
81
78
  - spec/spec_helper.rb
82
79
  - spec/stream_spec.rb