eventus 0.3.5 → 0.3.6

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