entity_store 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
-