entity_store 0.1.6 → 0.2.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 ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MTNjMDA0M2EyMWNmMWM5Y2U1NDc2MjMwOWU0NWQ5Mjk0ZWFlYjUxOA==
5
+ data.tar.gz: !binary |-
6
+ ZWMzNDEzNTYzYzU4ZjE1ZjVjOGNkZTJhMjQxMWMzOWUwNTllOGUwNQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MThjMmU5N2RhMzVjMjRkMGJmNDFjOTMxNjU5OWI5MzU3NWJkYzI5NDM4OTJm
10
+ ZjJjNzg3M2I4ZWJhMmIzMzUwYWFjOGU1Njk4OWMxY2Q0ZDA5ZGUyZjIzNGUz
11
+ MmQyMDE5YzgyOTFhZDI4Y2RlYzQzZDQ4M2Y3Yjg3YjYyNTdjNTU=
12
+ data.tar.gz: !binary |-
13
+ NDE3ODdjNGI2MzJiYzlhZDk0OTA2NzkwOTBlM2I1OGNmYWRhMjBlMTAyZjIw
14
+ ZTk0NmFmYTZmZWJjZTI3MmQzNDJkNmFlY2JhN2VkZWIzNGYzY2I2NTUxMDU1
15
+ ZTdlY2NkMjk4ZmU1MjExNmYwZjM5Yjk2N2Y4YzE1ZmQ3M2M0ZWQ=
data/lib/entity_store.rb CHANGED
@@ -1,68 +1,29 @@
1
1
  module EntityStore
2
2
 
3
- require 'hatchet'
4
- require 'entity_store/entity'
5
- require 'entity_store/entity_value'
6
- require 'entity_store/event'
7
- require 'entity_store/store'
8
- require 'entity_store/external_store'
9
- require 'entity_store/event_data_object'
10
- require 'entity_store/mongo_entity_store'
11
- require 'entity_store/event_bus'
12
- require 'entity_store/not_found'
13
- require 'entity_store/hash_serialization'
14
- require 'entity_store/attributes'
3
+ require_relative 'entity_store/logging'
4
+ require_relative 'entity_store/config'
5
+ require_relative 'entity_store/entity'
6
+ require_relative 'entity_store/entity_value'
7
+ require_relative 'entity_store/event'
8
+ require_relative 'entity_store/store'
9
+ require_relative 'entity_store/event_data_object'
10
+ require_relative 'entity_store/event_bus'
11
+ require_relative 'entity_store/not_found'
12
+ require_relative 'entity_store/hash_serialization'
13
+ require_relative 'entity_store/attributes'
14
+
15
+ if defined?(Mongo)
16
+ require_relative 'entity_store/mongo_entity_store'
17
+ require_relative 'entity_store/external_store'
18
+ end
15
19
 
16
20
  class << self
17
- attr_reader :mongo_connection, :external_mongo_connection, :entity_db, :external_db
18
- attr_accessor :connection_profile, :external_connection_profile
19
21
  def setup
20
- yield self
21
-
22
- @mongo_connection = open_store(@connection_profile)
23
- @entity_db = extract_db(@connection_profile)
24
- @external_mongo_connection = open_store(@external_connection_profile)
25
- @external_db = extract_db(@external_connection_profile)
22
+ yield EntityStore::Config.setup
26
23
  end
27
24
 
28
25
  def event_subscribers
29
- @_event_subscribers ||=[]
30
- end
31
-
32
- # Public - indicates the version increment that is used to
33
- # decided whether a snapshot of an entity should be created when it's saved
34
- def snapshot_threshold
35
- @_snapshot_threshold ||= 10
36
- end
37
-
38
- def snapshot_threshold=(value)
39
- @_snapshot_threshold = value
40
- end
41
-
42
- # Allows config to pass in a lambda or Proc to use as the type loader in place
43
- # of the default.
44
- # Original use case was migration of entity classes to new module namespace when
45
- # extracting to a shared library
46
- attr_accessor :type_loader
47
-
48
- def load_type(type_name)
49
- if EntityStore.type_loader
50
- EntityStore.type_loader.call(type_name)
51
- else
52
- type_name.split('::').inject(Object) {|obj, name| obj.const_get(name) }
53
- end
54
- end
55
-
56
- def open_store(url)
57
- Mongo::MongoClient.from_uri(url, :connect_timeout => connect_timeout)
58
- end
59
-
60
- def extract_db(url)
61
- URI.parse(url).path.gsub(/^\//, '')
62
- end
63
-
64
- def connect_timeout
65
- (ENV['ENTITY_STORE_CONNECT_TIMEOUT'] || '2').to_i
26
+ EntityStore::Config.event_subscribers
66
27
  end
67
28
  end
68
29
 
@@ -0,0 +1,53 @@
1
+ module EntityStore
2
+ module Config
3
+ class << self
4
+ # Stores
5
+ attr_accessor :store, :feed_store
6
+
7
+ # Allows config to pass in a lambda or Proc to use as the type loader in place
8
+ # of the default.
9
+ # Original use case was migration of entity classes to new module namespace when
10
+ # extracting to a shared library
11
+ attr_accessor :type_loader
12
+
13
+ # Logger can be assigned
14
+ attr_accessor :logger
15
+
16
+ def setup
17
+ yield self
18
+
19
+ raise StandardError.new("store not assigned") unless store
20
+ store.open
21
+ feed_store.open if feed_store
22
+ end
23
+
24
+ def event_subscribers
25
+ @_event_subscribers ||=[]
26
+ end
27
+
28
+ # Public - indicates the version increment that is used to
29
+ # decided whether a snapshot of an entity should be created when it's saved
30
+ def snapshot_threshold
31
+ @_snapshot_threshold ||= 10
32
+ end
33
+
34
+ def snapshot_threshold=(value)
35
+ @_snapshot_threshold = value
36
+ end
37
+
38
+
39
+ def load_type(type_name)
40
+ if EntityStore::Config.type_loader
41
+ EntityStore::Config.type_loader.call(type_name)
42
+ else
43
+ type_name.split('::').inject(Object) {|obj, name| obj.const_get(name) }
44
+ end
45
+ end
46
+
47
+ def connect_timeout
48
+ (ENV['ENTITY_STORE_CONNECT_TIMEOUT'] || '2').to_i
49
+ end
50
+ end
51
+
52
+ end
53
+ end
@@ -1,7 +1,5 @@
1
1
  module EntityStore
2
2
  module Entity
3
- include Hatchet
4
-
5
3
  attr_accessor :id
6
4
 
7
5
  def self.included(klass)
@@ -24,8 +24,17 @@ module EntityStore
24
24
  class_eval do
25
25
  names.each do |name|
26
26
  define_method "#{name}=" do |value|
27
- require 'time'
28
- instance_variable_set("@#{name}", value.kind_of?(String) ? Time.parse(value) : value)
27
+ if value.kind_of?(String)
28
+ # implementing parsing here rather than using std-lib Time.parse to
29
+ # allow portability across platforms
30
+ parts = /(?:(\d+))-(?:(\d+))-(?:(\d+))\s(?:(\d+)):(?:(\d+)):(?:(\d+))\s(?:(.+))/.match(value)
31
+ offset = parts[7].gsub(/\d{4}/) do |m| m.scan(/../).join(":") end
32
+ new_value = Time.new(parts[1].to_i, parts[2].to_i, parts[3].to_i, parts[4].to_i, parts[5].to_i, parts[6].to_i, offset)
33
+ else
34
+ new_value = value
35
+ end
36
+
37
+ instance_variable_set "@#{name}", new_value
29
38
  end
30
39
  define_method name do
31
40
  instance_variable_get "@#{name}"
@@ -1,18 +1,16 @@
1
1
  module EntityStore
2
2
  class EventBus
3
- include Hatchet
3
+ include Logging
4
4
 
5
5
  def publish(entity_type, event)
6
- publish_externally entity_type, event
7
-
8
- logger.debug { "publishing #{event.inspect}" }
6
+ publish_to_feed entity_type, event
9
7
 
10
8
  subscribers_to(event.receiver_name).each do |s|
11
9
  begin
12
10
  s.new.send(event.receiver_name, event)
13
- logger.debug { "called #{s.name}##{event.receiver_name} with #{event.inspect}" }
11
+ log_debug { "called #{s.name}##{event.receiver_name} with #{event.inspect}" }
14
12
  rescue => e
15
- logger.error "#{e.message} when calling #{s.name}##{event.receiver_name} with #{event.inspect}", e
13
+ log_error "#{e.message} when calling #{s.name}##{event.receiver_name} with #{event.inspect}", e
16
14
  end
17
15
  end
18
16
  end
@@ -22,15 +20,15 @@ module EntityStore
22
20
  end
23
21
 
24
22
  def subscribers
25
- EntityStore.event_subscribers
23
+ EntityStore::Config.event_subscribers
26
24
  end
27
25
 
28
- def publish_externally(entity_type, event)
29
- external_store.add_event(entity_type, event)
26
+ def publish_to_feed(entity_type, event)
27
+ feed_store.add_event(entity_type, event) if feed_store
30
28
  end
31
29
 
32
- def external_store
33
- @_external_store ||= ExternalStore.new
30
+ def feed_store
31
+ EntityStore::Config.feed_store
34
32
  end
35
33
 
36
34
  # Public - replay events of a given type to a given subscriber
@@ -42,19 +40,19 @@ module EntityStore
42
40
  # Returns nothing
43
41
  def replay(since, type, subscriber)
44
42
  max_items = 100
45
- event_data_objects = external_store.get_events(since, type, max_items)
43
+ event_data_objects = feed_store.get_events(since, type, max_items)
46
44
 
47
45
  while event_data_objects.count > 0 do
48
46
  event_data_objects.each do |event_data_object|
49
47
  begin
50
- event = EntityStore.load_type(event_data_object.type).new(event_data_object.attrs)
48
+ event = EntityStore::Config.load_type(event_data_object.type).new(event_data_object.attrs)
51
49
  subscriber.new.send(event.receiver_name, event)
52
- logger.info { "replayed #{event.inspect} to #{subscriber.name}##{event.receiver_name}" }
50
+ log_info { "replayed #{event.inspect} to #{subscriber.name}##{event.receiver_name}" }
53
51
  rescue => e
54
- logger.error "#{e.message} when replaying #{event_data_object.inspect} to #{subscriber}", e
52
+ log_error "#{e.message} when replaying #{event_data_object.inspect} to #{subscriber}", e
55
53
  end
56
54
  end
57
- event_data_objects = external_store.get_events(event_data_objects.last.id, type, max_items)
55
+ event_data_objects = feed_store.get_events(event_data_objects.last.id, type, max_items)
58
56
  end
59
57
  end
60
58
  end
@@ -4,9 +4,22 @@ require 'uri'
4
4
  module EntityStore
5
5
  class ExternalStore
6
6
  include Mongo
7
-
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
+ URI.parse(ExternalStore.connection_profile).path.gsub(/^\//, '')
18
+ end
19
+ end
20
+
8
21
  def open_connection
9
- EntityStore.external_mongo_connection.db(EntityStore.external_db)
22
+ ExternalStore.connection.db(ExternalStore.database)
10
23
  end
11
24
 
12
25
  def collection
@@ -9,15 +9,19 @@ module EntityStore
9
9
  # did use flatten but this came a-cropper when the attribute value was an array
10
10
  def attributes
11
11
  attrs = {}
12
- public_methods
13
- .select { |m| m =~ /\w\=$/ }
14
- .select { |m| respond_to?(m.to_s.chop) }
15
- .collect { |m| m.to_s.chop.to_sym }
12
+ attribute_methods
16
13
  .collect { |m| [m, attribute_value(send(m))] }
17
14
  .each do |item| attrs[item[0]] = item[1] end
18
15
  attrs
19
16
  end
20
17
 
18
+ def attribute_methods
19
+ public_methods
20
+ .select { |m| m =~ /\w\=$/ }
21
+ .collect { |m| m.to_s.chop.to_sym }
22
+ .select { |m| respond_to?(m) }
23
+ end
24
+
21
25
  def attribute_value(value)
22
26
  if value.respond_to?(:attributes)
23
27
  value.attributes
@@ -0,0 +1,17 @@
1
+ module EntityStore
2
+ module Logging
3
+
4
+ [:debug, :info, :warn].each do |level|
5
+ define_method("log_#{level}") do |message=nil, &block|
6
+ Config.logger.send(level, message || block) if Config.logger
7
+ end
8
+ end
9
+
10
+ def log_error(message, exception)
11
+ if Config.logger
12
+ Config.logger.error message
13
+ Config.logger.error exception.backtrace
14
+ end
15
+ end
16
+ end
17
+ end
@@ -4,18 +4,38 @@ require 'uri'
4
4
  module EntityStore
5
5
  class MongoEntityStore
6
6
  include Mongo
7
- include Hatchet
7
+ include Logging
8
8
 
9
- def open_connection
10
- EntityStore.mongo_connection.db(EntityStore.entity_db)
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)
15
+ end
16
+
17
+ def database
18
+ URI.parse(MongoEntityStore.connection_profile).path.gsub(/^\//, '')
19
+ end
20
+ end
21
+
22
+ def open
23
+ MongoEntityStore.connection.db(MongoEntityStore.database)
11
24
  end
12
25
 
13
26
  def entities
14
- @entities_collection ||= open_connection['entities']
27
+ @entities_collection ||= open['entities']
15
28
  end
16
29
 
17
30
  def events
18
- @events_collection ||= open_connection['entity_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
19
39
  end
20
40
 
21
41
  def ensure_indexes
@@ -63,24 +83,13 @@ module EntityStore
63
83
  def get_entity(id, raise_exception=false)
64
84
  if attrs = entities.find_one('_id' => BSON::ObjectId.from_string(id))
65
85
  begin
66
- entity = EntityStore.load_type(attrs['_type']).new(attrs['snapshot'] || {'id' => id, 'version' => attrs['version']})
86
+ entity_type = EntityStore::Config.load_type(attrs['_type'])
87
+ entity = entity_type.new(attrs['snapshot'] || {'id' => id, 'version' => attrs['version']})
67
88
  rescue => e
68
- logger.error "Error loading type #{attrs['_type']}", e
89
+ log_error "Error loading type #{attrs['_type']}", e
69
90
  raise
70
91
  end
71
-
72
- since_version = attrs['snapshot'] ? attrs['snapshot']['version'] : nil
73
-
74
- get_events(id, since_version).each do |event|
75
- begin
76
- event.apply(entity)
77
- logger.debug { "Applied #{event.inspect} to #{id}" }
78
- rescue => e
79
- logger.error "Failed to apply #{event.class.name} #{event.attributes} to #{id} with #{e.inspect}", e
80
- end
81
- entity.version = event.entity_version
82
- end
83
-
92
+
84
93
  entity
85
94
  else
86
95
  raise NotFound.new(id) if raise_exception
@@ -102,9 +111,9 @@ module EntityStore
102
111
 
103
112
  events.find(query, options).collect do |attrs|
104
113
  begin
105
- EntityStore.load_type(attrs['_type']).new(attrs)
114
+ EntityStore::Config.load_type(attrs['_type']).new(attrs)
106
115
  rescue => e
107
- logger.error "Error loading type #{attrs['_type']}", e
116
+ log_error "Error loading type #{attrs['_type']}", e
108
117
  nil
109
118
  end
110
119
  end.select { |e| !e.nil? }
@@ -1,9 +1,9 @@
1
1
  module EntityStore
2
2
  class Store
3
- include Hatchet
3
+ include Logging
4
4
 
5
5
  def storage_client
6
- @_storage_client ||= MongoEntityStore.new
6
+ @_storage_client ||= EntityStore::Config.store
7
7
  end
8
8
 
9
9
  def add(entity)
@@ -31,16 +31,16 @@ module EntityStore
31
31
  entity.id = storage_client.add_entity(entity)
32
32
  end
33
33
  add_events(entity)
34
- snapshot_entity(entity) if entity.version % EntityStore.snapshot_threshold == 0
34
+ snapshot_entity(entity) if entity.version % Config.snapshot_threshold == 0
35
35
  end
36
36
  entity
37
37
  rescue => e
38
- logger.error { "Store#do_save error: #{e.inspect} - #{entity.inspect}" }
38
+ log_error "Store#do_save error: #{e.inspect} - #{entity.inspect}", e
39
39
  raise e
40
40
  end
41
41
 
42
42
  def snapshot_entity(entity)
43
- logger.info { "Store#snapshot_entity : Snapshotting #{entity.id}"}
43
+ log_info { "Store#snapshot_entity : Snapshotting #{entity.id}"}
44
44
  storage_client.snapshot_entity(entity)
45
45
  end
46
46
 
@@ -64,6 +64,17 @@ module EntityStore
64
64
 
65
65
  def get(id, raise_exception=false)
66
66
  if entity = storage_client.get_entity(id, raise_exception)
67
+
68
+ storage_client.get_events(id, entity.version).each do |event|
69
+ begin
70
+ event.apply(entity)
71
+ log_debug { "Applied #{event.inspect} to #{id}" }
72
+ rescue => e
73
+ log_error "Failed to apply #{event.class.name} #{event.attributes} to #{id} with #{e.inspect}", e
74
+ end
75
+ entity.version = event.entity_version
76
+ end
77
+
67
78
  # assign this entity loader to allow lazy loading of related entities
68
79
  entity.related_entity_loader = self
69
80
  end
@@ -74,8 +85,7 @@ module EntityStore
74
85
  #
75
86
  # Returns nothing
76
87
  def clear_all
77
- storage_client.entities.drop
78
- storage_client.events.drop
88
+ storage_client.clear
79
89
  @_storage_client = nil
80
90
  end
81
91
 
@@ -1,3 +1,3 @@
1
1
  module EntityStore
2
- VERSION = "0.1.6".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ module Level1
4
+ module Level2
5
+ class MyClass
6
+ end
7
+ class AnotherClass
8
+ end
9
+ end
10
+ end
11
+
12
+ describe EntityStore::Config do
13
+
14
+ describe "load_type" do
15
+
16
+ subject { EntityStore::Config.load_type('Level1::Level2::MyClass') }
17
+
18
+ it "should be an Level1::Level2::MyClass" do
19
+ subject.should eq(Level1::Level2::MyClass)
20
+ end
21
+
22
+ context "when type_loader set" do
23
+ before(:each) do
24
+ EntityStore::Config.type_loader = lambda { |type_name|
25
+ Level1::Level2::AnotherClass
26
+ }
27
+ end
28
+
29
+ it "should return the result of that type loader" do
30
+ subject.should eq(Level1::Level2::AnotherClass)
31
+ end
32
+
33
+ after(:each) do
34
+ EntityStore::Config.type_loader = nil
35
+ end
36
+ end
37
+ end
38
+ end
@@ -23,7 +23,7 @@ describe EventBus do
23
23
  DummySubscriber.stub(:new) { @subscriber }
24
24
  @subscriber_class2 = mock("SubscriberClass", :instance_methods => ['bilge'], :name => "SubscriberClass")
25
25
  @event_bus.stub(:subscribers).and_return([DummySubscriber, @subscriber_class2])
26
- @event_bus.stub(:publish_externally)
26
+ @event_bus.stub(:publish_to_feed)
27
27
  end
28
28
 
29
29
  subject { @event_bus.publish(@entity_type, @event) }
@@ -37,21 +37,21 @@ describe EventBus do
37
37
  subject
38
38
  end
39
39
  it "publishes event to the external event push" do
40
- @event_bus.should_receive(:publish_externally).with(@entity_type, @event)
40
+ @event_bus.should_receive(:publish_to_feed).with(@entity_type, @event)
41
41
  subject
42
42
  end
43
43
  end
44
44
 
45
- describe ".publish_externally" do
45
+ describe ".publish_to_feed" do
46
46
  before(:each) do
47
- @external_store = mock(ExternalStore)
48
- @event_bus.stub(:external_store) { @external_store }
47
+ @feed_store = mock(ExternalStore)
48
+ @event_bus.stub(:feed_store) { @feed_store }
49
49
  end
50
50
 
51
- subject { @event_bus.publish_externally @entity_type, @event }
51
+ subject { @event_bus.publish_to_feed @entity_type, @event }
52
52
 
53
53
  it "should publish to the external store" do
54
- @external_store.should_receive(:add_event).with(@entity_type, @event)
54
+ @feed_store.should_receive(:add_event).with(@entity_type, @event)
55
55
  subject
56
56
  end
57
57
  end
@@ -63,18 +63,18 @@ describe EventBus do
63
63
  @subscriber = mock("Subscriber", :dummy_event => true)
64
64
  DummySubscriber.stub(:new) { @subscriber }
65
65
 
66
- @external_store = mock(ExternalStore)
66
+ @feed_store = mock(ExternalStore)
67
67
  @id = random_object_id
68
- @external_store.stub(:get_events) { |since| since == @id ? [] : [
68
+ @feed_store.stub(:get_events) { |since| since == @id ? [] : [
69
69
  EventDataObject.new('_id' => @id, '_type' => DummyEvent.name, 'name' => random_string)
70
70
  ]}
71
- @event_bus.stub(:external_store) { @external_store }
71
+ @event_bus.stub(:feed_store) { @feed_store }
72
72
  end
73
73
 
74
74
  subject { @event_bus.replay(@since, @type, DummySubscriber) }
75
75
 
76
76
  it "gets the events for that period" do
77
- @external_store.should_receive(:get_events).with(@since, @type, 100)
77
+ @feed_store.should_receive(:get_events).with(@since, @type, 100)
78
78
  subject
79
79
  end
80
80
  it "publishes them to the subscriber" do
@@ -12,6 +12,7 @@ end
12
12
 
13
13
  describe ExternalStore do
14
14
  before(:each) do
15
+ ExternalStore.connection_profile = "mongodb://localhost/external_store_default"
15
16
  ExternalStore.new.collection.drop
16
17
  @store = ExternalStore.new
17
18
  end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module MongoEntityStoreSpec
4
4
  class DummyEntity
5
- include Entity
5
+ include EntityStore::Entity
6
6
 
7
7
  attr_accessor :name, :description
8
8
 
@@ -11,7 +11,7 @@ end
11
11
 
12
12
  describe MongoEntityStore do
13
13
  before(:each) do
14
- EntityStore.connection_profile = "mongodb://localhost/entity_store_default"
14
+ MongoEntityStore.connection_profile = "mongodb://localhost/entity_store_default"
15
15
  @store = MongoEntityStore.new
16
16
  end
17
17
 
@@ -19,7 +19,7 @@ describe MongoEntityStore do
19
19
  before(:each) do
20
20
  @id = random_object_id
21
21
  @attrs = {
22
- '_type' => "MongoEntityStoreSpec::DummyEntity",
22
+ '_type' => MongoEntityStoreSpec::DummyEntity.name,
23
23
  'version' => @version = random_integer
24
24
  }
25
25
  @entity = MongoEntityStoreSpec::DummyEntity.new
@@ -42,18 +42,6 @@ describe MongoEntityStore do
42
42
  MongoEntityStoreSpec::DummyEntity.should_receive(:new).with({'id' => @id, 'version' => @version})
43
43
  subject
44
44
  end
45
- it "should retrieve it's events" do
46
- @store.should_receive(:get_events).with(@id, nil)
47
- subject
48
- end
49
- it "should apply each event to the entity" do
50
- @events.each do |event| event.should_receive(:apply).with(@entity) end
51
- subject
52
- end
53
- it "should set the entity version to that of the last event" do
54
- subject
55
- @entity.version.should eq(@events.last.entity_version)
56
- end
57
45
  it "should return the entity" do
58
46
  subject.should eq(@entity)
59
47
  end
@@ -68,10 +56,6 @@ describe MongoEntityStore do
68
56
  MongoEntityStoreSpec::DummyEntity.should_receive(:new).with(@attrs['snapshot'])
69
57
  subject
70
58
  end
71
- it "should load the events since the snapshot version" do
72
- @store.should_receive(:get_events).with(@id, @snapshot_version)
73
- subject
74
- end
75
59
  end
76
60
  end
77
61
 
@@ -80,7 +80,7 @@ describe Store do
80
80
  context "when entity has related entities loaded" do
81
81
  before(:each) do
82
82
  @entity = DummyEntityForStore.new(:id => random_string)
83
- @entity.version = random_integer * EntityStore.snapshot_threshold + 1
83
+ @entity.version = random_integer * EntityStore::Config.snapshot_threshold + 1
84
84
  @store = Store.new
85
85
  @related_entity = mock('Entity')
86
86
  @entity.stub(:loaded_related_entities) { [ @related_entity ] }
@@ -104,7 +104,7 @@ describe Store do
104
104
  before(:each) do
105
105
  @new_id = random_string
106
106
  @entity = DummyEntityForStore.new(:id => random_string)
107
- @entity.version = random_integer * EntityStore.snapshot_threshold
107
+ @entity.version = random_integer * EntityStore::Config.snapshot_threshold
108
108
  @storage_client = mock("StorageClient", :save_entity => true)
109
109
  @store = Store.new
110
110
  @store.stub(:add_events)
@@ -161,7 +161,7 @@ describe Store do
161
161
 
162
162
  context "when entity version is commensurate with snapshotting" do
163
163
  before(:each) do
164
- @entity.version = random_integer * EntityStore.snapshot_threshold - 1
164
+ @entity.version = random_integer * EntityStore::Config.snapshot_threshold - 1
165
165
  end
166
166
 
167
167
  it "should snapshot the entity" do
@@ -175,9 +175,12 @@ describe Store do
175
175
  describe "#get" do
176
176
  before(:each) do
177
177
  @id = random_integer
178
- @entity = DummyEntityForStore.new
178
+ @entity = DummyEntityForStore.new(id: random_string, version: random_integer)
179
179
  DummyEntityForStore.stub(:new).and_return(@entity)
180
- @events = [mock("Event", :apply => true), mock("Event", :apply => true)]
180
+ @events = [
181
+ mock("Event", apply: true, entity_version: @entity.version + 1),
182
+ mock("Event", apply: true, entity_version: @entity.version + 2)
183
+ ]
181
184
 
182
185
  @storage_client = mock("StorageClient", :get_entity => @entity, :get_events => @events)
183
186
  @store = Store.new
@@ -197,5 +200,17 @@ describe Store do
197
200
  it "should return a ride" do
198
201
  subject.should eq(@entity)
199
202
  end
203
+ it "should retrieve it's events" do
204
+ @storage_client.should_receive(:get_events).with(@id, @entity.version)
205
+ subject
206
+ end
207
+ it "should apply each event to the entity" do
208
+ @events.each do |event| event.should_receive(:apply).with(@entity) end
209
+ subject
210
+ end
211
+ it "should set the entity version to that of the last event" do
212
+ subject
213
+ @entity.version.should eq(@events.last.entity_version)
214
+ end
200
215
  end
201
216
  end
@@ -1,34 +1 @@
1
- require 'spec_helper'
2
-
3
- module Level1
4
- module Level2
5
- class MyClass
6
- end
7
- class AnotherClass
8
- end
9
- end
10
- end
11
-
12
- describe EntityStore do
13
-
14
- describe "load_type" do
15
-
16
- subject { EntityStore.load_type('Level1::Level2::MyClass') }
17
-
18
- it "should be an Level1::Level2::MyClass" do
19
- subject.should eq(Level1::Level2::MyClass)
20
- end
21
-
22
- context "when type_loader set" do
23
- before(:each) do
24
- EntityStore.type_loader = lambda { |type_name|
25
- Level1::Level2::AnotherClass
26
- }
27
- end
28
-
29
- it "should return the result of that type loader" do
30
- subject.should eq(Level1::Level2::AnotherClass)
31
- end
32
- end
33
- end
34
- end
1
+ require 'spec_helper'
data/spec/spec_helper.rb CHANGED
@@ -1,29 +1,18 @@
1
1
  require 'rake'
2
2
  require 'rspec'
3
+ require 'mongo'
3
4
  require "#{Rake.application.original_dir}/lib/entity_store"
4
5
 
5
6
  RSpec.configure do |config|
6
7
  config.color_enabled = true
7
8
  end
8
9
 
9
- Hatchet.configure do |config|
10
- # Reset the logging configuration
11
- config.reset!
12
- config.level :error
13
- # Use the format without time, etc so we don't duplicate it
14
- config.formatter = Hatchet::SimpleFormatter.new
15
- # Set up a STDOUT appender
16
- config.appenders << Hatchet::LoggerAppender.new do |appender|
17
- appender.logger = Logger.new(STDOUT)
18
- end
19
- end
20
-
21
10
  include EntityStore
22
11
 
23
- EntityStore.setup do |config|
24
- config.connection_profile = "mongodb://localhost/entity_store_test"
25
- config.external_connection_profile = "mongodb://localhost/external_entity_store_test"
26
- end
12
+ require 'logger'
13
+ logger = ::Logger.new(STDOUT)
14
+ logger.level = ::Logger::ERROR
15
+ EntityStore::Config.logger = logger
27
16
 
28
17
  def random_string
29
18
  (0...24).map{ ('a'..'z').to_a[rand(26)] }.join
metadata CHANGED
@@ -1,52 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: entity_store
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Adam Bird
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-12-31 00:00:00.000000000 Z
11
+ date: 2013-03-30 00:00:00.000000000 Z
13
12
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: mongo
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ~>
20
- - !ruby/object:Gem::Version
21
- version: '1.6'
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ~>
28
- - !ruby/object:Gem::Version
29
- version: '1.6'
30
- - !ruby/object:Gem::Dependency
31
- name: bson_ext
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ~>
36
- - !ruby/object:Gem::Version
37
- version: '1.6'
38
- type: :runtime
39
- prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ~>
44
- - !ruby/object:Gem::Version
45
- version: '1.6'
46
13
  - !ruby/object:Gem::Dependency
47
14
  name: hatchet
48
15
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
16
  requirements:
51
17
  - - ~>
52
18
  - !ruby/object:Gem::Version
@@ -54,12 +20,11 @@ dependencies:
54
20
  type: :runtime
55
21
  prerelease: false
56
22
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
23
  requirements:
59
24
  - - ~>
60
25
  - !ruby/object:Gem::Version
61
26
  version: 0.0.20
62
- description: Event sourced entity store with a Mongo body
27
+ description: Event sourced entity store with a replaceable body
63
28
  email: adam.bird@gmail.com
64
29
  executables: []
65
30
  extensions: []
@@ -74,12 +39,14 @@ files:
74
39
  - lib/entity_store/event_data_object.rb
75
40
  - lib/entity_store/external_store.rb
76
41
  - lib/entity_store/hash_serialization.rb
42
+ - lib/entity_store/logging.rb
77
43
  - lib/entity_store/mongo_entity_store.rb
78
44
  - lib/entity_store/not_found.rb
79
45
  - lib/entity_store/store.rb
80
46
  - lib/entity_store/version.rb
81
47
  - lib/entity_store.rb
82
48
  - lib/tasks/entity_store.rake
49
+ - spec/entity_store/config_spec.rb
83
50
  - spec/entity_store/entity_spec.rb
84
51
  - spec/entity_store/entity_value_spec.rb
85
52
  - spec/entity_store/event_bus_spec.rb
@@ -91,29 +58,29 @@ files:
91
58
  - spec/spec_helper.rb
92
59
  homepage: http://github.com/adambird/entity_store
93
60
  licenses: []
61
+ metadata: {}
94
62
  post_install_message:
95
63
  rdoc_options: []
96
64
  require_paths:
97
65
  - lib
98
66
  required_ruby_version: !ruby/object:Gem::Requirement
99
- none: false
100
67
  requirements:
101
68
  - - ! '>='
102
69
  - !ruby/object:Gem::Version
103
70
  version: '0'
104
71
  required_rubygems_version: !ruby/object:Gem::Requirement
105
- none: false
106
72
  requirements:
107
73
  - - ! '>='
108
74
  - !ruby/object:Gem::Version
109
75
  version: '0'
110
76
  requirements: []
111
77
  rubyforge_project:
112
- rubygems_version: 1.8.24
78
+ rubygems_version: 2.0.3
113
79
  signing_key:
114
- specification_version: 3
115
- summary: Event sourced entity store with a Mongo body
80
+ specification_version: 4
81
+ summary: Event sourced entity store with a replaceable body
116
82
  test_files:
83
+ - spec/entity_store/config_spec.rb
117
84
  - spec/entity_store/entity_spec.rb
118
85
  - spec/entity_store/entity_value_spec.rb
119
86
  - spec/entity_store/event_bus_spec.rb
@@ -123,4 +90,3 @@ test_files:
123
90
  - spec/entity_store/store_spec.rb
124
91
  - spec/entity_store_spec.rb
125
92
  - spec/spec_helper.rb
126
- has_rdoc: