entity_store 1.3.0 → 1.4.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
  SHA256:
3
- metadata.gz: 2d66518229bc1a1e8b67466d02c8da159937290bcb23821e7271d581e8c9ba8e
4
- data.tar.gz: 6ad5bb806da6d9741d35171e0833b647e98dab49685b842931641020344f1a06
3
+ metadata.gz: 1f071fa32e56d2d2754f6ea625d16f5157d672039f605c62d45f06c41c0e9743
4
+ data.tar.gz: 41e90b5b50d95eddc723e1290638a10cb05a50c49aaf996ea75d4547552d74b7
5
5
  SHA512:
6
- metadata.gz: bb6bbac0680c5b46ebce882cd171306585dd622cf6fcdaae2dda1e18ca789e072d781654a22ed52f19a90bad8c28bddb1a94987cca9141c904d6d79ef685b5d8
7
- data.tar.gz: 7efcc35670e23d51147fa8128fed71dda6308ebe9f5cd2bf934ca928a1006705bea03c80cd621a3ccaed79065ac0393f38963de2c387e45650b03f6d60321695
6
+ metadata.gz: 352fbec15f059e0401c1e8b0ec99fb07c1abbc3a9ab7da827fba24c60fb947448bca41a3bfe933b88dd815d7173167db1ab17589fa938d96c0038c37a3dd3daa
7
+ data.tar.gz: 79bf9b0ba01989b8e7b3da3af6a98cb5a6ea4cab703155e1965acbae7baecb421fba71693a901bdcef6258250bb7fa4881a4d9e4e896c5dea6e1075e833cc2e1
@@ -1,6 +1,4 @@
1
1
  module EntityStore
2
-
3
- require_relative 'entity_store/utils'
4
2
  require_relative 'entity_store/logging'
5
3
  require_relative 'entity_store/config'
6
4
  require_relative 'entity_store/time_factory'
@@ -4,9 +4,11 @@ module EntityStore
4
4
  # Stores
5
5
  attr_accessor :store, :feed_store
6
6
 
7
+ attr_accessor :cache_event_subscribers
8
+
7
9
  # 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
+ # of the default.
11
+ # Original use case was migration of entity classes to new module namespace when
10
12
  # extracting to a shared library
11
13
  attr_accessor :type_loader
12
14
 
@@ -17,15 +19,15 @@ module EntityStore
17
19
  yield self
18
20
 
19
21
  raise StandardError.new("store not assigned") unless store
20
- store.open
22
+ store.open
21
23
  feed_store.open if feed_store
22
24
  end
23
-
25
+
24
26
  def event_subscribers
25
27
  @_event_subscribers ||=[]
26
28
  end
27
-
28
- # Public - indicates the version increment that is used to
29
+
30
+ # Public - indicates the version increment that is used to
29
31
  # decided whether a snapshot of an entity should be created when it's saved
30
32
  def snapshot_threshold
31
33
  @_snapshot_threshold ||= 10
@@ -35,7 +37,6 @@ module EntityStore
35
37
  @_snapshot_threshold = value
36
38
  end
37
39
 
38
-
39
40
  def load_type(type_name)
40
41
  if EntityStore::Config.type_loader
41
42
  EntityStore::Config.type_loader.call(type_name)
@@ -50,4 +51,4 @@ module EntityStore
50
51
  end
51
52
 
52
53
  end
53
- end
54
+ end
@@ -27,18 +27,48 @@ module EntityStore
27
27
  end
28
28
 
29
29
  def subscribers_to(event_name)
30
- subscribers.select { |s| s.instance_methods.include?(event_name.to_sym) }
30
+ subscriber_lookup[event_name.to_sym].dup
31
31
  end
32
32
 
33
33
  def subscribers_to_all
34
- subscribers.select { |s| s.instance_methods.include?(ALL_METHOD) }
34
+ subscribers_to(ALL_METHOD)
35
+ end
36
+
37
+ def subscriber_lookup_cache
38
+ @@lookup_cache ||= Hash.new
39
+ end
40
+
41
+ def subscriber_lookup
42
+ return generate_subscriber_lookup unless EntityStore::Config.cache_event_subscribers
43
+
44
+ @lookup ||= begin
45
+ lookup_cache_key = event_subscribers.map(&:to_s).join
46
+
47
+ if subscriber_lookup_cache[lookup_cache_key]
48
+ subscriber_lookup_cache[lookup_cache_key]
49
+ else
50
+ subscriber_lookup_cache[lookup_cache_key] = generate_subscriber_lookup
51
+ end
52
+ end
53
+ end
54
+
55
+ def generate_subscriber_lookup
56
+ lookup = Hash.new { |h, k| h[k] = Array.new }
57
+
58
+ subscribers.each do |s|
59
+ s.instance_methods.each do |m|
60
+ lookup[m] << s
61
+ end
62
+ end
63
+
64
+ lookup
35
65
  end
36
66
 
37
67
  def subscribers
38
68
  event_subscribers.map do |subscriber|
39
69
  case subscriber
40
70
  when String
41
- Utils.get_type_constant(subscriber)
71
+ EntityStore::Config.load_type(subscriber)
42
72
  else
43
73
  subscriber
44
74
  end
@@ -53,6 +53,33 @@ module EntityStore
53
53
  raise e
54
54
  end
55
55
 
56
+ # Upsert an entity where events have existed previously
57
+ # for example when migrating data
58
+ #
59
+ # Please note this method requires that the events expose their id property
60
+ # as a method named _id.
61
+ #
62
+ def upsert(entity)
63
+ unless entity.pending_events.empty?
64
+ entity.version = entity.pending_events.map(&:entity_version).max || 1
65
+
66
+ if entity.id
67
+ storage_client.save_entity(entity)
68
+ else
69
+ entity.id = storage_client.add_entity(entity)
70
+ end
71
+
72
+ upsert_events(entity)
73
+
74
+ # publish version increment signal event to the bus
75
+ event_bus.publish(entity.type, entity.generate_version_incremented_event)
76
+ end
77
+ entity
78
+ rescue => e
79
+ log_error "Store#upsert error: #{e.inspect} - #{entity.inspect}", e
80
+ raise e
81
+ end
82
+
56
83
  def snapshot_entity(entity)
57
84
  log_info { "Store#snapshot_entity : Snapshotting #{entity.id}"}
58
85
  storage_client.snapshot_entity(entity)
@@ -85,6 +112,22 @@ module EntityStore
85
112
  entity.clear_pending_events
86
113
  end
87
114
 
115
+ def upsert_events(entity)
116
+ items = entity.pending_events.map do |event|
117
+ event.entity_id ||= entity.id.to_s
118
+ event.entity_version ||= entity.version
119
+ event
120
+ end
121
+
122
+ filtered_items = storage_client.upsert_events(items)
123
+
124
+ yield if block_given?
125
+
126
+ filtered_items.each { |e| event_bus.publish(entity.type, e) }
127
+
128
+ entity.clear_pending_events
129
+ end
130
+
88
131
  def get!(id)
89
132
  get(id, true)
90
133
  end
@@ -1,3 +1,3 @@
1
1
  module EntityStore
2
- VERSION = "1.3.0".freeze
2
+ VERSION = "1.4.0".freeze
3
3
  end
@@ -74,6 +74,39 @@ describe Store do
74
74
 
75
75
  end
76
76
 
77
+ describe "#upsert_events" do
78
+ before(:each) do
79
+ @entity = DummyEntityForStore.new(:name => random_string)
80
+ @entity.id = random_string
81
+ @entity.version = random_integer
82
+ @entity.pending_events << double(Event, :entity_id => @entity.id, :entity_version => @entity.version)
83
+ @entity.pending_events << double(Event, :entity_id => @entity.id, :entity_version => @entity.version)
84
+ @entity.pending_events << double(Event, :entity_id => @entity.id, :entity_version => @entity.version)
85
+ @storage_client = double("StorageClient", :upsert_events => filtered_events)
86
+ @store = Store.new
87
+ @store.stub(:storage_client) { @storage_client }
88
+ @event_bus = double(EventBus, :publish => true)
89
+ @store.stub(:event_bus) { @event_bus}
90
+ end
91
+
92
+ subject { @store.upsert_events(@entity) }
93
+
94
+ let(:filtered_events) { @entity.pending_events.take(2) }
95
+
96
+ it "adds each of the events" do
97
+ @storage_client.should_receive(:upsert_events).with(@entity.pending_events)
98
+ subject
99
+ end
100
+
101
+ it "publishes each event to the EventBus" do
102
+ filtered_events.each do |e|
103
+ @event_bus.should_receive(:publish).with(@entity.type, e)
104
+ end
105
+ subject
106
+ end
107
+
108
+ end
109
+
77
110
  describe "#save" do
78
111
 
79
112
  before(:each) do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: entity_store
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.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: 2018-10-24 00:00:00.000000000 Z
11
+ date: 2018-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bson
@@ -57,7 +57,6 @@ files:
57
57
  - lib/entity_store/not_found.rb
58
58
  - lib/entity_store/store.rb
59
59
  - lib/entity_store/time_factory.rb
60
- - lib/entity_store/utils.rb
61
60
  - lib/entity_store/version.rb
62
61
  - lib/tasks/entity_store.rake
63
62
  - spec/entity_store/config_spec.rb
@@ -88,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
87
  version: '0'
89
88
  requirements: []
90
89
  rubyforge_project:
91
- rubygems_version: 2.7.4
90
+ rubygems_version: 2.7.7
92
91
  signing_key:
93
92
  specification_version: 4
94
93
  summary: Event sourced entity store with a replaceable body
@@ -1,8 +0,0 @@
1
- module EntityStore
2
- module Utils
3
- def self.get_type_constant(type_name)
4
- type_name.split('::').inject(Object) { |obj, name| obj.const_get(name) }
5
- end
6
- end
7
- end
8
-