entity_store 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,13 +1,13 @@
1
1
  module EntityStore
2
2
  module Event
3
- attr_accessor :entity_id
4
-
3
+ attr_accessor :entity_id, :entity_version
4
+
5
5
  def initialize(attrs={})
6
- attrs.each_pair do |key, value|
6
+ attrs.each_pair do |key, value|
7
7
  send("#{key}=", value) if respond_to?("#{key}=")
8
8
  end
9
9
  end
10
-
10
+
11
11
  def receiver_name
12
12
  elements = self.class.name.split('::')
13
13
  elements[elements.count - 1].
@@ -16,20 +16,20 @@ module EntityStore
16
16
  tr("-", "_").
17
17
  downcase
18
18
  end
19
-
19
+
20
20
  def attributes
21
21
  Hash[*public_methods.select {|m| m =~ /\w\=$/}.collect do |m|
22
22
  attribute_name = m.to_s.chop.to_sym
23
23
  [attribute_name, send(attribute_name).respond_to?(:attributes) ? send(attribute_name).attributes : send(attribute_name)]
24
24
  end.flatten]
25
25
  end
26
-
26
+
27
27
  def self.included(klass)
28
28
  klass.class_eval do
29
29
  extend ClassMethods
30
30
  end
31
31
  end
32
-
32
+
33
33
  module ClassMethods
34
34
  def time_attribute(*names)
35
35
  class_eval do
@@ -44,7 +44,7 @@ module EntityStore
44
44
  end
45
45
  end
46
46
  end
47
-
47
+
48
48
  def entity_value_attribute(name, klass)
49
49
  define_method(name) { instance_variable_get("@#{name}") }
50
50
  define_method("#{name}=") do |value|
@@ -3,7 +3,9 @@ module EntityStore
3
3
  class << self
4
4
  def publish(entity_type, event)
5
5
  publish_externally entity_type, event
6
-
6
+
7
+ EntityStore.logger.debug { "publishing #{event.inspect}" }
8
+
7
9
  subscribers_to(event.receiver_name).each do |s|
8
10
  begin
9
11
  s.new.send(event.receiver_name, event)
@@ -17,15 +19,15 @@ module EntityStore
17
19
  def subscribers_to(event_name)
18
20
  subscribers.select { |s| s.instance_methods.include?(event_name.to_sym) }
19
21
  end
20
-
22
+
21
23
  def subscribers
22
24
  EntityStore.event_subscribers
23
25
  end
24
-
26
+
25
27
  def publish_externally(entity_type, event)
26
28
  external_store.add_event(entity_type, event)
27
29
  end
28
-
30
+
29
31
  def external_store
30
32
  @_external_store ||= ExternalStore.new
31
33
  end
@@ -3,16 +3,16 @@ module EntityStore
3
3
  def storage_client
4
4
  @storage_client || MongoEntityStore.new
5
5
  end
6
-
7
- def add(entity)
8
- entity.id = storage_client.add_entity(entity)
6
+
7
+ def add(entity)
8
+ entity.id = storage_client.add_entity(entity)
9
9
  add_events(entity)
10
10
  return entity
11
11
  rescue => e
12
12
  EntityStore.logger.error { "Store#add error: #{e.inspect} - #{entity.inspect}" }
13
13
  raise e
14
14
  end
15
-
15
+
16
16
  def save(entity)
17
17
  # need to look at concurrency if we start storing version on client
18
18
  entity.version += 1
@@ -23,10 +23,11 @@ module EntityStore
23
23
  EntityStore.logger.error { "Store#save error: #{e.inspect} - #{entity.inspect}" }
24
24
  raise e
25
25
  end
26
-
26
+
27
27
  def add_events(entity)
28
28
  entity.pending_events.each do |e|
29
29
  e.entity_id = entity.id.to_s
30
+ e.entity_version = entity.version
30
31
  storage_client.add_event(e)
31
32
  end
32
33
  entity.pending_events.each {|e| EventBus.publish(entity.type, e) }
@@ -35,22 +36,22 @@ module EntityStore
35
36
  def get!(id)
36
37
  get(id, true)
37
38
  end
38
-
39
+
39
40
  def get(id, raise_exception=false)
40
41
  if entity = storage_client.get_entity(id, raise_exception)
41
- storage_client.get_events(id).each { |e| e.apply(entity) }
42
- end
42
+ storage_client.get_events(id).each { |e| e.apply(entity) }
43
+ end
43
44
  return entity
44
45
  end
45
-
46
+
46
47
  # Public : USE AT YOUR PERIL this clears the ENTIRE data store
47
- #
48
+ #
48
49
  # Returns nothing
49
50
  def clear_all
50
51
  storage_client.entities.drop
51
52
  storage_client.events.drop
52
53
  @storage_client = nil
53
54
  end
54
-
55
+
55
56
  end
56
57
  end
@@ -1,3 +1,3 @@
1
1
  module EntityStore
2
- VERSION = "0.0.2".freeze
2
+ VERSION = "0.0.3".freeze
3
3
  end
@@ -16,18 +16,22 @@ end
16
16
  describe Event do
17
17
  before(:each) do
18
18
  @id = random_integer
19
+ @version = random_integer
19
20
  @name = random_string
20
21
  @time = random_time
21
22
  @town = random_string
22
23
  @county = random_string
23
24
  end
24
25
  describe "#initialize" do
25
-
26
- subject { DummyEvent.new({:entity_id => @id, :name => @name, :updated_at => @time, :sent_at => nil, :address => {:town => @town, :county => @county}})}
27
-
26
+
27
+ subject { DummyEvent.new({:entity_id => @id, :entity_version => @version, :name => @name, :updated_at => @time, :sent_at => nil, :address => {:town => @town, :county => @county}})}
28
+
28
29
  it "should set entity_id" do
29
30
  subject.entity_id.should eq(@id)
30
31
  end
32
+ it "should set entity_version" do
33
+ subject.entity_version.should eq(@version)
34
+ end
31
35
  it "should set name" do
32
36
  subject.name.should eq(@name)
33
37
  end
@@ -41,27 +45,27 @@ describe Event do
41
45
  subject.address.county.should eq(@county)
42
46
  end
43
47
  end
44
-
48
+
45
49
  describe "#attributes" do
46
50
  before(:each) do
47
- @event = DummyEvent.new(:entity_id => @id, :name => @name, :updated_at => @time, :address => DummyValue.new(:town => @town, :county => @county))
51
+ @event = DummyEvent.new(:entity_id => @id, :entity_version => @version, :name => @name, :updated_at => @time, :address => DummyValue.new(:town => @town, :county => @county))
48
52
  end
49
-
53
+
50
54
  subject { @event.attributes }
51
-
55
+
52
56
  it "returns a hash of the attributes" do
53
- subject.should eq({:entity_id => @id, :name => @name, :updated_at => @time, :sent_at => nil, :address => {:town => @town, :county => @county}})
57
+ subject.should eq({:entity_id => @id, :entity_version => @version, :name => @name, :updated_at => @time, :sent_at => nil, :address => {:town => @town, :county => @county}})
54
58
  end
55
59
  end
56
-
60
+
57
61
  describe ".time_attribute" do
58
62
  before(:each) do
59
63
  @event = DummyEvent.new
60
64
  @time = random_time
61
65
  end
62
- context "updated_at" do
66
+ context "updated_at" do
63
67
  subject { @event.updated_at = @time.to_s }
64
-
68
+
65
69
  it "parses the time field when added as a string" do
66
70
  subject
67
71
  @event.updated_at.to_i.should eq(@time.to_i)
@@ -69,14 +73,14 @@ describe Event do
69
73
  end
70
74
  context "sent_at" do
71
75
  subject { @event.updated_at = @time.to_s }
72
-
76
+
73
77
  it "parses the time field when added as a string" do
74
78
  subject
75
79
  @event.updated_at.to_i.should eq(@time.to_i)
76
80
  end
77
81
  end
78
82
  end
79
-
83
+
80
84
  describe ".value_attribute" do
81
85
  before(:each) do
82
86
  @event = DummyEvent.new
@@ -2,9 +2,9 @@ require 'spec_helper'
2
2
 
3
3
  class DummyEntity
4
4
  include Entity
5
-
5
+
6
6
  attr_accessor :name
7
-
7
+
8
8
  def initialize(name)
9
9
  @name = name
10
10
  end
@@ -20,9 +20,9 @@ describe Store do
20
20
  @store.stub(:add_events)
21
21
  @store.stub(:storage_client) { @storage_client }
22
22
  end
23
-
23
+
24
24
  subject { @store.add(@entity) }
25
-
25
+
26
26
  it "adds the new entity to the store" do
27
27
  @storage_client.should_receive(:add_entity).with(@entity)
28
28
  subject
@@ -33,23 +33,24 @@ describe Store do
33
33
  end
34
34
  it "returns a reference to the ride" do
35
35
  subject.should eq(@entity)
36
- end
36
+ end
37
37
  end
38
38
 
39
39
  describe "#add_events" do
40
40
  before(:each) do
41
41
  @entity = DummyEntity.new(random_string)
42
42
  @entity.id = random_string
43
- @entity.pending_events << mock(Event, :entity_id= => true)
44
- @entity.pending_events << mock(Event, :entity_id= => true)
43
+ @entity.version = random_integer
44
+ @entity.pending_events << mock(Event, :entity_id= => true, :entity_version= => true)
45
+ @entity.pending_events << mock(Event, :entity_id= => true, :entity_version= => true)
45
46
  @storage_client = mock("StorageClient", :add_event => true)
46
47
  @store = Store.new
47
48
  @store.stub(:storage_client) { @storage_client }
48
49
  EventBus.stub(:publish)
49
50
  end
50
-
51
+
51
52
  subject { @store.add_events(@entity) }
52
-
53
+
53
54
  it "adds each of the events" do
54
55
  @entity.pending_events.each do |e|
55
56
  @storage_client.should_receive(:add_event).with(e)
@@ -62,15 +63,21 @@ describe Store do
62
63
  end
63
64
  subject
64
65
  end
66
+ it "should assign the current entity version to each event" do
67
+ @entity.pending_events.each do |e|
68
+ e.should_receive(:entity_version=).with(@entity.version)
69
+ end
70
+ subject
71
+ end
65
72
  it "publishes each event to the EventBus" do
66
73
  @entity.pending_events.each do |e|
67
74
  EventBus.should_receive(:publish).with(@entity.type, e)
68
75
  end
69
76
  subject
70
77
  end
71
-
78
+
72
79
  end
73
-
80
+
74
81
  describe "#save" do
75
82
  before(:each) do
76
83
  @new_id = random_string
@@ -80,9 +87,9 @@ describe Store do
80
87
  @store.stub(:add_events)
81
88
  @store.stub(:storage_client) { @storage_client }
82
89
  end
83
-
90
+
84
91
  subject { @store.save(@entity) }
85
-
92
+
86
93
  it "increments the entity version number" do
87
94
  @entity.should_receive(:version=).with(@entity.version + 1)
88
95
  subject
@@ -99,21 +106,21 @@ describe Store do
99
106
  subject.should eq(@entity)
100
107
  end
101
108
  end
102
-
109
+
103
110
  describe "#get" do
104
111
  before(:each) do
105
112
  @id = random_integer
106
113
  @entity = DummyEntity.new(random_string)
107
114
  DummyEntity.stub(:new).and_return(@ride)
108
115
  @events = [mock("Event", :apply => true), mock("Event", :apply => true)]
109
-
116
+
110
117
  @storage_client = mock("StorageClient", :get_entity => @entity, :get_events => @events)
111
118
  @store = Store.new
112
119
  @store.stub(:storage_client) { @storage_client }
113
120
  end
114
-
121
+
115
122
  subject { @store.get(@id) }
116
-
123
+
117
124
  it "should retrieve object from the storage client" do
118
125
  @storage_client.should_receive(:get_entity).with(@id, false)
119
126
  subject
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: entity_store
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-30 00:00:00.000000000 Z
12
+ date: 2012-07-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mongo
16
- requirement: &70160207835100 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: '1.6'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70160207835100
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.6'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: bson_ext
27
- requirement: &70160207834240 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ~>
@@ -32,7 +37,12 @@ dependencies:
32
37
  version: '1.6'
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *70160207834240
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.6'
36
46
  description: Event sourced entity store with a Mongo body
37
47
  email: adam.bird@gmail.com
38
48
  executables: []
@@ -80,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
90
  version: '0'
81
91
  requirements: []
82
92
  rubyforge_project:
83
- rubygems_version: 1.8.10
93
+ rubygems_version: 1.8.24
84
94
  signing_key:
85
95
  specification_version: 3
86
96
  summary: Event sourced entity store with a Mongo body