entity_store 0.6.0 → 1.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2fd6deacb63e070d4f7052598ccc5e79679d1052
4
- data.tar.gz: 4c3fcfb0cae2e37aaa699c39a3730dda39d9f217
3
+ metadata.gz: c1bf9f57ff36a9e94b582cec4dd38d5364536455
4
+ data.tar.gz: 27b4160e5a19ee2e315a8a4f526e7bfd46f0c39b
5
5
  SHA512:
6
- metadata.gz: 676503735ad66f25dd174831c840ac9ec2d42616783aeaed0c8ba37fe50c33c00cf1e227284d84d4e08e76de9280c0f7b094e990dbe445f7937e1975545de288
7
- data.tar.gz: 00516945f8fd853b07c982c823da8e911d8fee23630ba2f0ab68d751f36c2f277225722ed1055b8e849eea3969b32d1bfe3d1642e90f9cf4b4d891571760e238
6
+ metadata.gz: 763f6f18705899dcf36b63b526a7dd97dd40896409401a2405a1609c3ea4f026c344c7f0e8d66af5d8e1f77c5558dc98da044346b598064c02233e3c01e5fbae
7
+ data.tar.gz: cb1c725e9c7befe55fe237510bc20a37ab4752c375e7395373489ddfd8064f28b31de00c9752c8c73f58a2bcea2e68b5d6071dc6a6dc6b453dd362da4929aaaf
@@ -57,6 +57,10 @@ module EntityStore
57
57
  storage_client.remove_snapshots type
58
58
  end
59
59
 
60
+ def clear_entity_events(id, excluded_types = [])
61
+ storage_client.clear_entity_events(id, excluded_types)
62
+ end
63
+
60
64
  def add_events(entity)
61
65
  items = entity.pending_events.map do |event|
62
66
  event.entity_id = entity.id.to_s
@@ -1,3 +1,3 @@
1
1
  module EntityStore
2
- VERSION = "0.6.0".freeze
2
+ VERSION = "1.0.0".freeze
3
3
  end
data/lib/entity_store.rb CHANGED
@@ -14,9 +14,6 @@ module EntityStore
14
14
  require_relative 'entity_store/event_bus'
15
15
  require_relative 'entity_store/not_found'
16
16
 
17
- require_relative 'entity_store/mongo_entity_store'
18
- require_relative 'entity_store/external_store'
19
-
20
17
  class << self
21
18
  def setup
22
19
  yield EntityStore::Config.setup
@@ -23,6 +23,9 @@ class DummyAllSubscriber
23
23
  end
24
24
  end
25
25
 
26
+ class DummyExternalStore
27
+ end
28
+
26
29
  describe EventBus do
27
30
  before(:each) do
28
31
  @entity_type = random_string
@@ -68,7 +71,7 @@ describe EventBus do
68
71
 
69
72
  describe ".publish_to_feed" do
70
73
  before(:each) do
71
- @feed_store = double(ExternalStore)
74
+ @feed_store = double(DummyExternalStore)
72
75
  @event_bus.stub(:feed_store) { @feed_store }
73
76
  end
74
77
 
@@ -87,7 +90,7 @@ describe EventBus do
87
90
  @subscriber = double("Subscriber", :dummy_event => true)
88
91
  DummySubscriber.stub(:new) { @subscriber }
89
92
 
90
- @feed_store = double(ExternalStore)
93
+ @feed_store = double(DummyExternalStore)
91
94
  @id = random_object_id
92
95
  @feed_store.stub(:get_events) { |since| since == @id ? [] : [
93
96
  EventDataObject.new('_id' => @id, '_type' => DummyEvent.name, 'name' => random_string)
@@ -30,12 +30,60 @@ class DummyEntitySubscriber
30
30
  end
31
31
  end
32
32
 
33
+ class DummyStore
34
+ def open
35
+ end
36
+
37
+ def entities
38
+ @entities ||= {}
39
+ end
40
+
41
+ def events
42
+ @events ||= {}
43
+ end
44
+
45
+ def add_entity(entity, id = BSON::ObjectId.new)
46
+ entities[id] = entity
47
+ id.to_s
48
+ end
49
+
50
+ def add_events(items)
51
+ items.each do |item|
52
+ events[item.entity_id] ||= []
53
+ events[item.entity_id] << item
54
+ end
55
+ end
56
+
57
+ def get_entities(ids, options={})
58
+ result = []
59
+ ids.each do |id|
60
+ if entity = entities[BSON::ObjectId.from_string(id)]
61
+ result << entity
62
+ end
63
+ end
64
+
65
+ result
66
+ end
67
+
68
+ def get_events(attrs)
69
+ result = {}
70
+
71
+ attrs.each do |attr|
72
+ result[attr[:id]] = events[attr[:id]]
73
+ end
74
+
75
+ result
76
+ end
77
+
78
+ def save_entity(entity)
79
+ entities[entity.id] = entity
80
+ end
81
+ end
82
+
33
83
  describe "end to end" do
34
84
  before(:each) do
35
- MongoEntityStore.connection_profile = "mongodb://localhost/entity_store_test"
36
-
37
85
  EntityStore::Config.setup do |config|
38
- config.store = MongoEntityStore.new
86
+ config.store = DummyStore.new
39
87
  config.event_subscribers << DummyEntitySubscriber
40
88
  end
41
89
  end
@@ -55,4 +103,4 @@ describe "end to end" do
55
103
  EntityStore::Store.new.get(@entity.id).name.should eq(name)
56
104
  end
57
105
  end
58
- end
106
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rake'
2
2
  require 'rspec'
3
- require 'mongo'
4
3
  require 'hatchet'
4
+ require 'bson'
5
5
 
6
6
  require "#{Rake.application.original_dir}/lib/entity_store"
7
7
 
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: entity_store
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Bird
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-09 00:00:00.000000000 Z
11
+ date: 2018-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: mongo
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.8'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.8'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: bson
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -66,10 +52,8 @@ files:
66
52
  - lib/entity_store/event.rb
67
53
  - lib/entity_store/event_bus.rb
68
54
  - lib/entity_store/event_data_object.rb
69
- - lib/entity_store/external_store.rb
70
55
  - lib/entity_store/hash_serialization.rb
71
56
  - lib/entity_store/logging.rb
72
- - lib/entity_store/mongo_entity_store.rb
73
57
  - lib/entity_store/not_found.rb
74
58
  - lib/entity_store/store.rb
75
59
  - lib/entity_store/time_factory.rb
@@ -81,8 +65,6 @@ files:
81
65
  - spec/entity_store/entity_value_spec.rb
82
66
  - spec/entity_store/event_bus_spec.rb
83
67
  - spec/entity_store/event_spec.rb
84
- - spec/entity_store/external_store_spec.rb
85
- - spec/entity_store/mongo_entity_store_spec.rb
86
68
  - spec/entity_store/store_spec.rb
87
69
  - spec/entity_store_spec.rb
88
70
  - spec/spec_helper.rb
@@ -106,18 +88,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
88
  version: '0'
107
89
  requirements: []
108
90
  rubyforge_project:
109
- rubygems_version: 2.6.6
91
+ rubygems_version: 2.4.5.1
110
92
  signing_key:
111
93
  specification_version: 4
112
94
  summary: Event sourced entity store with a replaceable body
113
95
  test_files:
96
+ - spec/spec_helper.rb
97
+ - spec/entity_store_spec.rb
98
+ - spec/entity_store/entity_value_spec.rb
114
99
  - spec/entity_store/config_spec.rb
115
100
  - spec/entity_store/entity_spec.rb
116
- - spec/entity_store/entity_value_spec.rb
117
- - spec/entity_store/event_bus_spec.rb
118
101
  - spec/entity_store/event_spec.rb
119
- - spec/entity_store/external_store_spec.rb
120
- - spec/entity_store/mongo_entity_store_spec.rb
102
+ - spec/entity_store/event_bus_spec.rb
121
103
  - spec/entity_store/store_spec.rb
122
- - spec/entity_store_spec.rb
123
- - spec/spec_helper.rb
@@ -1,62 +0,0 @@
1
- require 'mongo'
2
- require 'uri'
3
-
4
- module EntityStore
5
- class ExternalStore
6
- include Mongo
7
-
8
- class << self
9
- attr_accessor :connection_profile
10
- attr_writer :connect_timeout
11
-
12
- def connection
13
- @_connection ||= Mongo::MongoClient.from_uri(ExternalStore.connection_profile, :connect_timeout => EntityStore::Config.connect_timeout)
14
- end
15
-
16
- def database
17
- @_database ||= ExternalStore.connection_profile.split('/').last
18
- end
19
- end
20
-
21
- def open
22
- ExternalStore.connection.db(ExternalStore.database)
23
- end
24
-
25
- def collection
26
- @_collection ||= open['events']
27
- end
28
-
29
- def ensure_indexes
30
- collection.ensure_index([['_type', Mongo::ASCENDING], ['_id', Mongo::ASCENDING]])
31
- end
32
-
33
- def add_event(entity_type, event)
34
- collection.insert({
35
- '_entity_type' => entity_type, '_type' => event.class.name
36
- }.merge(event.attributes)
37
- )
38
- end
39
-
40
- # Public - get events since a Time or ID
41
- #
42
- # since - Time or String id to filter events from
43
- # type - String optionally filter the event type to return (default=nil)
44
- # max_items - Fixnum max items to return (default=100)
45
- #
46
- # Returns Enumerable EventDataObject
47
- def get_events(since, type=nil, max_items=100)
48
- since_id = since.is_a?(Time) ? BSON::ObjectId.from_time(since) : BSON::ObjectId.from_string(since)
49
-
50
- query = { '_id' => { '$gt' => since_id } }
51
- query['_type'] = type if type
52
-
53
- options = {
54
- :sort => [['_id', Mongo::ASCENDING]],
55
- :limit => max_items
56
- }
57
-
58
- collection.find(query, options).collect { |e| EventDataObject.new(e)}
59
- end
60
-
61
- end
62
- end
@@ -1,196 +0,0 @@
1
- require 'mongo'
2
- require 'uri'
3
-
4
- module EntityStore
5
- class MongoEntityStore
6
- include Mongo
7
- include Logging
8
-
9
- class << self
10
- attr_accessor :connection_profile
11
- attr_writer :connect_timeout
12
-
13
- def connection
14
- @_connection ||= Mongo::MongoClient.from_uri(MongoEntityStore.connection_profile, :connect_timeout => EntityStore::Config.connect_timeout, :refresh_mode => :sync)
15
- end
16
-
17
- def database
18
- @_database ||= MongoEntityStore.connection_profile.split('/').last.split('?').first
19
- end
20
- end
21
-
22
- def open
23
- MongoEntityStore.connection.db(MongoEntityStore.database)
24
- end
25
-
26
- def entities
27
- @entities_collection ||= open['entities']
28
- end
29
-
30
- def events
31
- @events_collection ||= open['entity_events']
32
- end
33
-
34
- def clear
35
- entities.drop
36
- @entities_collection = nil
37
- events.drop
38
- @events_collection = nil
39
- end
40
-
41
- def ensure_indexes
42
- events.ensure_index([['_entity_id', Mongo::ASCENDING], ['_id', Mongo::ASCENDING]])
43
- events.ensure_index([['_entity_id', Mongo::ASCENDING], ['entity_version', Mongo::ASCENDING], ['_id', Mongo::ASCENDING]])
44
- end
45
-
46
- def add_entity(entity, id = BSON::ObjectId.new)
47
- entities.insert('_id' => id, '_type' => entity.class.name, 'version' => entity.version).to_s
48
- end
49
-
50
- def save_entity(entity)
51
- entities.update({'_id' => BSON::ObjectId.from_string(entity.id)}, { '$set' => { 'version' => entity.version } })
52
- end
53
-
54
- # Public: create a snapshot of the entity and store in the entities collection
55
- #
56
- def snapshot_entity(entity)
57
- query = {'_id' => BSON::ObjectId.from_string(entity.id)}
58
- updates = { '$set' => { 'snapshot' => entity.attributes } }
59
-
60
- if entity.class.respond_to? :entity_store_snapshot_key
61
- # If there is a snapshot key, store it too
62
- updates['$set']['snapshot_key'] = entity.class.entity_store_snapshot_key
63
- else
64
- # Otherwise, make sure there isn't one set
65
- updates['$unset'] = { 'snapshot_key' => '' }
66
- end
67
-
68
- entities.update(query, updates, { :upsert => true} )
69
- end
70
-
71
- # Public - remove the snapshot for an entity
72
- #
73
- def remove_entity_snapshot(id)
74
- entities.update({'_id' => BSON::ObjectId.from_string(id)}, { '$unset' => { 'snapshot' => 1}})
75
- end
76
-
77
- # Public: remove all snapshots
78
- #
79
- # type - String optional class name for the entity
80
- #
81
- def remove_snapshots type=nil
82
- query = {}
83
- query['_type'] = type if type
84
- entities.update(query, { '$unset' => { 'snapshot' => 1 } }, { multi: true })
85
- end
86
-
87
- def add_events(items)
88
- events_with_id = items.map { |e| [ BSON::ObjectId.new, e ] }
89
- add_events_with_ids(events_with_id)
90
- end
91
-
92
- def add_events_with_ids(event_id_map)
93
- docs = event_id_map.map do |id, event|
94
- {
95
- '_id' => id,
96
- '_type' => event.class.name,
97
- '_entity_id' => BSON::ObjectId.from_string(event.entity_id)
98
- }.merge(event.attributes)
99
- end
100
-
101
- events.insert(docs)
102
- end
103
-
104
- # Public: loads the entity from the store, including any available snapshots
105
- # then loads the events to complete the state
106
- #
107
- # ids - Array of Strings representation of BSON::ObjectId
108
- # options - Hash of options (default: {})
109
- # :raise_exception - Boolean (default: true)
110
- #
111
- # Returns an array of entities
112
- def get_entities(ids, options={})
113
-
114
- object_ids = ids.map do |id|
115
- begin
116
- BSON::ObjectId.from_string(id)
117
- rescue BSON::InvalidObjectId
118
- raise NotFound.new(id) if options.fetch(:raise_exception, true)
119
- nil
120
- end
121
- end
122
-
123
- entities.find('_id' => { '$in' => object_ids }).map do |attrs|
124
- begin
125
- entity_type = EntityStore::Config.load_type(attrs['_type'])
126
-
127
- # Check if there is a snapshot key in use
128
- if entity_type.respond_to? :entity_store_snapshot_key
129
- active_key = entity_type.entity_store_snapshot_key
130
- # Discard the snapshot if the keys don't match
131
- attrs.delete('snapshot') unless active_key == attrs['snapshot_key']
132
- end
133
-
134
- entity = entity_type.new(attrs['snapshot'] || {'id' => attrs['_id'].to_s })
135
- rescue => e
136
- log_error "Error loading type #{attrs['_type']}", e
137
- raise
138
- end
139
-
140
- entity
141
- end
142
-
143
- end
144
-
145
- # Public: get events for an array of criteria objects
146
- # because each entity could have a different reference
147
- # version this allows optional criteria to be specifed
148
- #
149
- #
150
- # criteria - Hash :id mandatory, :since_version optional
151
- #
152
- # Examples
153
- #
154
- # get_events_for_criteria([ { id: "23232323"}, { id: "2398429834", since_version: 4 } ] )
155
- #
156
- # Returns Hash with id as key and Array of Event instances as value
157
- def get_events(criteria)
158
- return {} if criteria.empty?
159
-
160
- query_items = criteria.map do |item|
161
- raise ArgumentError.new(":id missing from criteria") unless item[:id]
162
- item_query = { '_entity_id' => BSON::ObjectId.from_string(item[:id]) }
163
- item_query['entity_version'] = { '$gt' => item[:since_version] } if item[:since_version]
164
- item_query
165
- end
166
-
167
- query = { '$or' => query_items }
168
-
169
- result = Hash[ criteria.map { |item| [ item[:id], [] ] } ]
170
-
171
- events.find(query).each do |attrs|
172
- result[attrs['_entity_id'].to_s] << attrs
173
- end
174
-
175
- result.each do |id, events|
176
- # Have to do the sort client side as otherwise the query will not use
177
- # indexes (http://docs.mongodb.org/manual/reference/operator/query/or/#or-and-sort-operations)
178
- events.sort_by! { |attrs| [attrs['entity_version'], attrs['_id'].to_s] }
179
-
180
- # Convert the attributes into event objects
181
- events.map! do |attrs|
182
- begin
183
- EntityStore::Config.load_type(attrs['_type']).new(attrs)
184
- rescue => e
185
- log_error "Error loading type #{attrs['_type']}", e
186
- nil
187
- end
188
- end
189
-
190
- events.compact!
191
- end
192
-
193
- result
194
- end
195
- end
196
- end
@@ -1,124 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class DummyEvent
4
- include Event
5
- attr_accessor :name
6
- end
7
-
8
- class DummyEventTwo
9
- include Event
10
- attr_accessor :name
11
- end
12
-
13
- describe ExternalStore do
14
- before(:each) do
15
- ExternalStore.connection_profile = "mongodb://localhost/external_store_default"
16
- ExternalStore.new.collection.drop
17
- @store = ExternalStore.new
18
- end
19
- describe "#add_event" do
20
- before(:each) do
21
- @entity_type = random_string
22
- @event = DummyEvent.new(:name => random_string, :entity_id => random_object_id)
23
- end
24
-
25
- subject { @store.add_event(@entity_type, @event) }
26
-
27
- it "creates a record in the collection" do
28
- subject
29
- item = @store.collection.find_one
30
- item['_entity_type'].should eq(@entity_type)
31
- item['_type'].should eq(@event.class.name)
32
- item['name'].should eq(@event.name)
33
- item['entity_id'].should eq(@event.entity_id)
34
- end
35
- end
36
-
37
- describe "#get_events" do
38
- before(:each) do
39
- @reference_time = Time.now
40
- @ids = (-2..2).collect { |i| BSON::ObjectId.from_time(@reference_time + i) }
41
-
42
- @store.collection.insert({'_id' => @ids[0], '_type' => 'DummyEvent'})
43
- @store.collection.insert({'_id' => @ids[1], '_type' => 'DummyEventTwo'})
44
- @store.collection.insert({'_id' => @ids[2], '_type' => 'DummyEvent'})
45
- @store.collection.insert({'_id' => @ids[3], '_type' => 'DummyEventTwo'})
46
- @store.collection.insert({'_id' => @ids[4], '_type' => 'DummyEvent'})
47
- end
48
-
49
- subject { @store.get_events @since, @type }
50
-
51
- context "when time passed as since" do
52
- before(:each) do
53
- @since = @reference_time
54
- end
55
- context "when no type filter" do
56
- before(:each) do
57
- @type = nil
58
- @results = subject
59
- end
60
- it "returns two records" do
61
- @results.count.should eq(2)
62
- end
63
- it "it returns the 4th item first" do
64
- @results.first.id.should eq(@ids[3].to_s)
65
- end
66
- it "it returns the 5th item second" do
67
- @results[1].id.should eq(@ids[4].to_s)
68
- end
69
- end
70
- context "when type filter 'DummyEventTwo' passed" do
71
- before(:each) do
72
- @type = "DummyEventTwo"
73
- @results = subject
74
- end
75
- it "returns 1 record" do
76
- @results.count.should eq(1)
77
- end
78
- it "returns the 4th item" do
79
- @results.first.id.should eq(@ids[3].to_s)
80
- end
81
- end
82
- end
83
-
84
- context "when id passed as since" do
85
- before(:each) do
86
- @since = @ids[1].to_s
87
- end
88
- context "when no type filter passed" do
89
- before(:each) do
90
- @type = nil
91
- @results = subject
92
- end
93
- it "returns 3 records" do
94
- @results.count.should eq(3)
95
- end
96
- it "it returns the 3rd item first" do
97
- @results.first.id.should eq(@ids[2].to_s)
98
- end
99
- it "it returns the 4th item second" do
100
- @results[1].id.should eq(@ids[3].to_s)
101
- end
102
- it "it returns the 5th item second" do
103
- @results[2].id.should eq(@ids[4].to_s)
104
- end
105
- end
106
- context "when type filter 'DummyEvent' passed" do
107
- before(:each) do
108
- @type = "DummyEvent"
109
- @results = subject
110
- end
111
- it "returns 2 records" do
112
- @results.count.should eq(2)
113
- end
114
- it "returns the 3rd item" do
115
- @results.first.id.should eq(@ids[2].to_s)
116
- end
117
- it "returns the 5th item" do
118
- @results[1].id.should eq(@ids[4].to_s)
119
- end
120
- end
121
- end
122
- end
123
-
124
- end
@@ -1,200 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe MongoEntityStore do
4
- class DummyEntity
5
- include EntityStore::Entity
6
-
7
- attr_accessor :name, :description
8
-
9
- def set_name(new_name)
10
- record_event DummyEntityNameSet.new(name: new_name)
11
- end
12
- end
13
-
14
- class DummyEntityWithSnapshotKey < DummyEntity
15
- def self.entity_store_snapshot_key
16
- @entity_store_snapshot_key ||= 1
17
- end
18
-
19
- def self.increment_entity_store_snapshot_key!
20
- @entity_store_snapshot_key = entity_store_snapshot_key + 1
21
- end
22
- end
23
-
24
- class DummyEntityNameSet
25
- include EntityStore::Event
26
-
27
- attr_accessor :name
28
-
29
- def apply(entity)
30
- entity.name = self.name
31
- end
32
-
33
- def ==(other)
34
- # Crude check relying on inspect, ok for tests
35
- self.inspect == other.inspect
36
- end
37
- end
38
-
39
- let(:store) do
40
- MongoEntityStore.connection_profile = "mongodb://localhost/entity_store_default"
41
- MongoEntityStore.new
42
- end
43
-
44
- describe "event storage" do
45
- let(:entity_id) { random_object_id }
46
-
47
- let(:first_event) { DummyEntityNameSet.new(:entity_id => entity_id, :entity_version => 1, :name => random_string) }
48
- let(:second_event) { DummyEntityNameSet.new(:entity_id => entity_id, :entity_version => 2, :name => random_string) }
49
- let(:third_event) { DummyEntityNameSet.new(:entity_id => entity_id, :entity_version => 2, :name => random_string) }
50
- let(:unrelated_event) { DummyEntityNameSet.new(:entity_id => random_object_id, :entity_version => 4, :name => random_string) }
51
- let(:fourth_event) { DummyEntityNameSet.new(:entity_id => entity_id, :entity_version => 3, :name => random_string) }
52
-
53
- before do
54
- store.add_events([ second_event, unrelated_event, first_event, third_event, fourth_event ])
55
- end
56
-
57
- subject { store.get_events( [{ id: event_entity_id, since_version: since_version }])[event_entity_id] }
58
-
59
- context "all events" do
60
- let(:event_entity_id) { entity_id }
61
- let(:since_version) { 0 }
62
-
63
- it "should return the four events in order" do
64
- subject.should == [first_event, second_event, third_event, fourth_event]
65
- end
66
- end
67
-
68
- context "subset of events" do
69
- let(:event_entity_id) { entity_id }
70
- let(:since_version) { second_event.entity_version }
71
-
72
- it "should only include events greater than the given version" do
73
- subject.should == [ fourth_event ]
74
- end
75
- end
76
-
77
- context "no events" do
78
- let(:event_entity_id) { random_object_id }
79
- let(:since_version) { 0 }
80
-
81
- it "should return an empty array" do
82
- subject.should be_empty
83
- end
84
- end
85
- end
86
-
87
- describe "#get_entities" do
88
- let(:entity_class) { DummyEntity }
89
-
90
- let(:saved_entity) do
91
- entity = entity_class.new(:name => random_string, :description => random_string)
92
- entity.id = store.add_entity(entity)
93
- entity
94
- end
95
-
96
- let(:id) { saved_entity.id }
97
- let(:options) { { } }
98
-
99
- subject { store.get_entities( [ id ], options) }
100
-
101
- it "should retrieve an entity from the store with the same ID" do
102
- subject.first.id.should == saved_entity.id
103
- end
104
-
105
- it "should retrieve an entity from the store with the same class" do
106
- subject.first.class.should == saved_entity.class
107
- end
108
-
109
- it "should have the same version" do
110
- subject.first.version.should == saved_entity.version
111
- end
112
-
113
- context "when a snapshot does not exist" do
114
- it "should not have set the name" do
115
- subject.first.name.should be_nil
116
- end
117
- end
118
-
119
- context "when a snapshot exists" do
120
- before do
121
- saved_entity.version = 10
122
- store.snapshot_entity(saved_entity)
123
- end
124
-
125
- context "when a snapshot key not in use" do
126
- it "should have set the name" do
127
- subject.first.name.should == saved_entity.name
128
- end
129
- end
130
-
131
- context "when a snapshot key is in use" do
132
- let(:entity_class) { DummyEntityWithSnapshotKey }
133
-
134
- context "when the key matches the class's key" do
135
- it "should have set the name" do
136
- subject.first.name.should == saved_entity.name
137
- end
138
- end
139
-
140
- context "when the key does not match the class's key" do
141
- before do
142
- entity_class.increment_entity_store_snapshot_key!
143
- end
144
-
145
- it "should ignore the invalidated snapshot" do
146
- subject.first.name.should be_nil
147
- end
148
- end
149
- end
150
- end
151
-
152
- describe "context when enable exceptions" do
153
- let(:options) do
154
- { raise_exception: true }
155
- end
156
-
157
- context "when invalid id format passed" do
158
- let(:id) { random_string }
159
-
160
- it "should raise not found" do
161
- expect { subject }.to raise_error(NotFound)
162
- end
163
- end
164
- end
165
-
166
- end
167
-
168
- describe "#snapshot_entity" do
169
- let(:entity_class) { DummyEntity }
170
-
171
- let(:entity) do
172
- entity_class.new(:id => random_object_id, :version => random_integer, :name => random_string)
173
- end
174
-
175
- let(:saved_entity) do
176
- store.entities.find_one({'_id' => BSON::ObjectId.from_string(entity.id)})
177
- end
178
-
179
- subject { store.snapshot_entity(entity) }
180
-
181
- it "should add a snaphot to the entity record" do
182
- subject
183
- snapshot = saved_entity['snapshot']
184
-
185
- snapshot['id'].should eq(entity.id)
186
- snapshot['version'].should eq(entity.version)
187
- snapshot['name'].should eq(entity.name)
188
- snapshot['description'].should eq(entity.description)
189
- end
190
-
191
- context "entity with snapshot key" do
192
- let(:entity_class) { DummyEntityWithSnapshotKey }
193
-
194
- it "should store the snapshot key" do
195
- subject
196
- saved_entity['snapshot_key'].should == entity.class.entity_store_snapshot_key
197
- end
198
- end
199
- end
200
- end