entity_store 0.0.5 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
data/lib/entity_store/entity.rb
CHANGED
@@ -1,8 +1,42 @@
|
|
1
1
|
module EntityStore
|
2
2
|
module Entity
|
3
3
|
attr_accessor :id
|
4
|
+
|
5
|
+
# Holds a reference to the store used to load this entity so the same store
|
6
|
+
# can be used for related entities
|
7
|
+
attr_accessor :related_entity_loader
|
8
|
+
|
4
9
|
attr_writer :version
|
5
10
|
|
11
|
+
def self.included(klass)
|
12
|
+
klass.class_eval do
|
13
|
+
extend ClassMethods
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
|
19
|
+
def related_entities(*names)
|
20
|
+
names.each do |name|
|
21
|
+
# attr accessor for the id
|
22
|
+
define_method("#{name}_id") { instance_variable_get("@#{name}_id")}
|
23
|
+
define_method("#{name}_id=") do |value| instance_variable_set("@#{name}_id", value) end
|
24
|
+
|
25
|
+
# lazy loader for related entity
|
26
|
+
define_method(name) {
|
27
|
+
if instance_variable_get("@#{name}_id") && related_entity_loader
|
28
|
+
instance_variable_get("@_#{name}") || instance_variable_set("@_#{name}", related_entity_loader.get(instance_variable_get("@#{name}_id")))
|
29
|
+
end
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
define_method(:loaded_related_entities) {
|
34
|
+
names.collect{ |name| instance_variable_get("@_#{name}") }.select{|entity| !entity.nil? }
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
6
40
|
def initialize(attr={})
|
7
41
|
attr.each_pair { |k,v| self.send("#{k}=", v) }
|
8
42
|
end
|
@@ -11,12 +11,12 @@ module EntityStore
|
|
11
11
|
|
12
12
|
def open_store
|
13
13
|
uri = URI.parse(EntityStore.connection_profile)
|
14
|
-
connection = Connection.from_uri(EntityStore.connection_profile)
|
14
|
+
connection = Connection.from_uri(EntityStore.connection_profile, :connect_timeout => connect_timeout)
|
15
15
|
connection.db(uri.path.gsub(/^\//, ''))
|
16
16
|
end
|
17
17
|
|
18
18
|
def connect_timeout
|
19
|
-
ENV['ENTITY_STORE_CONNECT_TIMEOUT'] || '
|
19
|
+
(ENV['ENTITY_STORE_CONNECT_TIMEOUT'] || '2').to_i
|
20
20
|
end
|
21
21
|
|
22
22
|
def entities
|
data/lib/entity_store/store.rb
CHANGED
@@ -7,20 +7,32 @@ module EntityStore
|
|
7
7
|
def add(entity)
|
8
8
|
entity.id = storage_client.add_entity(entity)
|
9
9
|
add_events(entity)
|
10
|
-
|
10
|
+
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
|
+
do_save entity
|
18
|
+
entity.loaded_related_entities.each do |e| do_save e end if entity.respond_to?(:loaded_related_entities)
|
19
|
+
entity
|
20
|
+
end
|
21
|
+
|
22
|
+
def do_save(entity)
|
17
23
|
# need to look at concurrency if we start storing version on client
|
18
|
-
entity.
|
19
|
-
|
20
|
-
|
21
|
-
|
24
|
+
unless entity.pending_events.empty?
|
25
|
+
entity.version += 1
|
26
|
+
if entity.id
|
27
|
+
storage_client.save_entity(entity)
|
28
|
+
else
|
29
|
+
entity.id = storage_client.add_entity(entity)
|
30
|
+
end
|
31
|
+
add_events(entity)
|
32
|
+
end
|
33
|
+
entity
|
22
34
|
rescue => e
|
23
|
-
EntityStore.logger.error { "Store#
|
35
|
+
EntityStore.logger.error { "Store#do_save error: #{e.inspect} - #{entity.inspect}" }
|
24
36
|
raise e
|
25
37
|
end
|
26
38
|
|
@@ -40,8 +52,10 @@ module EntityStore
|
|
40
52
|
def get(id, raise_exception=false)
|
41
53
|
if entity = storage_client.get_entity(id, raise_exception)
|
42
54
|
storage_client.get_events(id).each { |e| e.apply(entity) }
|
55
|
+
# assign this entity loader to allow lazy loading of related entities
|
56
|
+
entity.related_entity_loader = self
|
43
57
|
end
|
44
|
-
|
58
|
+
entity
|
45
59
|
end
|
46
60
|
|
47
61
|
# Public : USE AT YOUR PERIL this clears the ENTIRE data store
|
data/lib/entity_store/version.rb
CHANGED
@@ -0,0 +1,69 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class DummyEntity
|
4
|
+
include Entity
|
5
|
+
|
6
|
+
related_entities :club, :user
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Entity do
|
11
|
+
describe ".related_entities" do
|
12
|
+
before(:each) do
|
13
|
+
@entity_loader = mock(Store)
|
14
|
+
@club = mock('Entity', :id => random_string)
|
15
|
+
@user = mock('Entity', :id => random_string)
|
16
|
+
@entity = DummyEntity.new(:related_entity_loader => @entity_loader, :club_id => @club.id, :user_id => @user.id)
|
17
|
+
@entity_loader.stub(:get) { |id|
|
18
|
+
case id
|
19
|
+
when @club.id
|
20
|
+
@club
|
21
|
+
when @user.id
|
22
|
+
@user
|
23
|
+
end
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should have the club_id set" do
|
28
|
+
@entity.club_id.should eq(@club.id)
|
29
|
+
end
|
30
|
+
it "should load club" do
|
31
|
+
@entity.club.should eq(@club)
|
32
|
+
end
|
33
|
+
it "should call entity_loader with club id" do
|
34
|
+
@entity_loader.should_receive(:get).with(@club.id)
|
35
|
+
@entity.club
|
36
|
+
end
|
37
|
+
it "should have the user_id set" do
|
38
|
+
@entity.user_id.should eq(@user.id)
|
39
|
+
end
|
40
|
+
it "should load user" do
|
41
|
+
@entity.user.should eq(@user)
|
42
|
+
end
|
43
|
+
it "should call entity_loader with user id" do
|
44
|
+
@entity_loader.should_receive(:get).with(@user.id)
|
45
|
+
@entity.user
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when only user loaded" do
|
49
|
+
before(:each) do
|
50
|
+
@entity.user
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should only have user in the loaded related entities collection" do
|
54
|
+
@entity.loaded_related_entities.should eq([@user])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when both user and club loaded" do
|
59
|
+
before(:each) do
|
60
|
+
@entity.club
|
61
|
+
@entity.user
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should only have user in the loaded related entities collection" do
|
65
|
+
@entity.loaded_related_entities.should eq([@club, @user])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -1,20 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class DummyEntityForStore
|
4
4
|
include Entity
|
5
5
|
|
6
6
|
attr_accessor :name
|
7
7
|
|
8
|
-
def initialize(name)
|
9
|
-
@name = name
|
10
|
-
end
|
11
8
|
end
|
12
9
|
|
13
10
|
describe Store do
|
14
11
|
describe "#add" do
|
15
12
|
before(:each) do
|
16
13
|
@new_id = random_string
|
17
|
-
@entity =
|
14
|
+
@entity = DummyEntityForStore.new(:name => random_string)
|
18
15
|
@storage_client = mock("StorageClient", :add_entity => @new_id)
|
19
16
|
@store = Store.new
|
20
17
|
@store.stub(:add_events)
|
@@ -38,7 +35,7 @@ describe Store do
|
|
38
35
|
|
39
36
|
describe "#add_events" do
|
40
37
|
before(:each) do
|
41
|
-
@entity =
|
38
|
+
@entity = DummyEntityForStore.new(:name => random_string)
|
42
39
|
@entity.id = random_string
|
43
40
|
@entity.version = random_integer
|
44
41
|
@entity.pending_events << mock(Event, :entity_id= => true, :entity_version= => true)
|
@@ -79,16 +76,41 @@ describe Store do
|
|
79
76
|
end
|
80
77
|
|
81
78
|
describe "#save" do
|
79
|
+
context "when entity has related entities loaded" do
|
80
|
+
before(:each) do
|
81
|
+
@entity = DummyEntityForStore.new(:id => random_string)
|
82
|
+
@store = Store.new
|
83
|
+
@related_entity = mock('Entity')
|
84
|
+
@entity.stub(:loaded_related_entities) { [ @related_entity ] }
|
85
|
+
@store.stub(:do_save)
|
86
|
+
end
|
87
|
+
|
88
|
+
subject { @store.save(@entity) }
|
89
|
+
|
90
|
+
it "should save the entity" do
|
91
|
+
@store.should_receive(:do_save).with(@entity)
|
92
|
+
subject
|
93
|
+
end
|
94
|
+
it "should save them as well" do
|
95
|
+
@store.should_receive(:do_save).with(@related_entity)
|
96
|
+
subject
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#do_save" do
|
82
103
|
before(:each) do
|
83
104
|
@new_id = random_string
|
84
|
-
@entity =
|
105
|
+
@entity = DummyEntityForStore.new(:id => random_string)
|
85
106
|
@storage_client = mock("StorageClient", :save_entity => true)
|
86
107
|
@store = Store.new
|
87
108
|
@store.stub(:add_events)
|
88
109
|
@store.stub(:storage_client) { @storage_client }
|
110
|
+
@entity.stub(:pending_events) { [ mock('Event') ] }
|
89
111
|
end
|
90
112
|
|
91
|
-
subject { @store.
|
113
|
+
subject { @store.do_save(@entity) }
|
92
114
|
|
93
115
|
it "increments the entity version number" do
|
94
116
|
@entity.should_receive(:version=).with(@entity.version + 1)
|
@@ -102,16 +124,40 @@ describe Store do
|
|
102
124
|
@store.should_receive(:add_events).with(@entity)
|
103
125
|
subject
|
104
126
|
end
|
105
|
-
it "returns a reference to the
|
127
|
+
it "returns a reference to the entity" do
|
106
128
|
subject.should eq(@entity)
|
107
129
|
end
|
130
|
+
context "when no pending events" do
|
131
|
+
before(:each) do
|
132
|
+
@entity.stub(:pending_events) { [] }
|
133
|
+
end
|
134
|
+
it "should not save the entity" do
|
135
|
+
@storage_client.should_not_receive(:save_entity)
|
136
|
+
subject
|
137
|
+
end
|
138
|
+
it "should not add the events" do
|
139
|
+
@storage_client.should_not_receive(:add_events)
|
140
|
+
subject
|
141
|
+
end
|
142
|
+
end
|
143
|
+
context "when entity doesn't have an id" do
|
144
|
+
before(:each) do
|
145
|
+
@entity.id = nil
|
146
|
+
@id = random_string
|
147
|
+
@storage_client.stub(:add_entity) { @id }
|
148
|
+
end
|
149
|
+
it "should add the entity" do
|
150
|
+
@storage_client.should_receive(:add_entity).with(@entity)
|
151
|
+
subject
|
152
|
+
end
|
153
|
+
end
|
108
154
|
end
|
109
155
|
|
110
156
|
describe "#get" do
|
111
157
|
before(:each) do
|
112
158
|
@id = random_integer
|
113
|
-
@entity =
|
114
|
-
|
159
|
+
@entity = DummyEntityForStore.new
|
160
|
+
DummyEntityForStore.stub(:new).and_return(@ride)
|
115
161
|
@events = [mock("Event", :apply => true), mock("Event", :apply => true)]
|
116
162
|
|
117
163
|
@storage_client = mock("StorageClient", :get_entity => @entity, :get_events => @events)
|
@@ -135,6 +181,9 @@ describe Store do
|
|
135
181
|
end
|
136
182
|
subject
|
137
183
|
end
|
184
|
+
it "should assign itself as the related_entity_loader" do
|
185
|
+
subject.related_entity_loader.should eq(@store)
|
186
|
+
end
|
138
187
|
it "should return a ride" do
|
139
188
|
subject.should eq(@entity)
|
140
189
|
end
|
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.
|
4
|
+
version: 0.0.7
|
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-
|
12
|
+
date: 2012-10-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mongo
|
@@ -62,6 +62,7 @@ files:
|
|
62
62
|
- lib/entity_store/version.rb
|
63
63
|
- lib/entity_store.rb
|
64
64
|
- lib/tasks/entity_store.rake
|
65
|
+
- spec/entity_store/entity_spec.rb
|
65
66
|
- spec/entity_store/entity_value_spec.rb
|
66
67
|
- spec/entity_store/event_bus_spec.rb
|
67
68
|
- spec/entity_store/event_spec.rb
|
@@ -95,6 +96,7 @@ signing_key:
|
|
95
96
|
specification_version: 3
|
96
97
|
summary: Event sourced entity store with a Mongo body
|
97
98
|
test_files:
|
99
|
+
- spec/entity_store/entity_spec.rb
|
98
100
|
- spec/entity_store/entity_value_spec.rb
|
99
101
|
- spec/entity_store/event_bus_spec.rb
|
100
102
|
- spec/entity_store/event_spec.rb
|