entity_store 0.0.5 → 0.0.7
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/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
|