nexia_event_store 0.9.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/event_store/snapshot.rb +45 -14
- data/lib/event_store/version.rb +1 -1
- data/spec/event_store/snapshot_spec.rb +64 -20
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2dba3805be9987a863b9c80cad063ff5ce6ecd2
|
4
|
+
data.tar.gz: 735780ad87bad4795370e51bcf22b71f85184e51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b3aac7d78671e3b9ffd7c136d88ebded20358121fdf9759762cdd846e697325972725e1183a570412e475fe7fbed5bc3fd9768e885037efb1cf848e122f9ad5
|
7
|
+
data.tar.gz: 4da1989af164abf4802e5e963491fd68a2da8993154f568107ed8e02d0e8f1e88b4a576371032ee787c16906151a89fa0fabef2e3d94286c69c9d21343d79ddd
|
data/lib/event_store/snapshot.rb
CHANGED
@@ -41,12 +41,7 @@ module EventStore
|
|
41
41
|
|
42
42
|
t = Time.now
|
43
43
|
result_hash = events_hash.inject([]) do |snapshot, (key, value)|
|
44
|
-
|
45
|
-
raw_event = value.split(EventStore::SNAPSHOT_DELIMITER)
|
46
|
-
event_id = raw_event.first.to_i
|
47
|
-
serialized_event = EventStore.unescape_bytea(raw_event[1])
|
48
|
-
occurred_at = Time.parse(raw_event.last)
|
49
|
-
snapshot + [SerializedEvent.new(fully_qualified_name, serialized_event, event_id, occurred_at)]
|
44
|
+
snapshot + [serialized_event_from_snapshot_event(key, value)]
|
50
45
|
end
|
51
46
|
logger.debug { "#{self.class.name} serializing events took #{Time.now - t} seconds" }
|
52
47
|
result_hash.sort_by(&:event_id).each { |e| yield e }
|
@@ -99,16 +94,47 @@ module EventStore
|
|
99
94
|
end
|
100
95
|
|
101
96
|
def update_fqns!(logger = default_logger)
|
102
|
-
|
97
|
+
logger.debug { "Replacing FQNs in snapshot events" }
|
98
|
+
updated_events = replace_fqns_in_snapshot_hash(read_with_rebuild(logger)) { |fqn| yield fqn }
|
99
|
+
|
100
|
+
logger.debug { "Replacing FQNs in snapshot event ids" }
|
103
101
|
updated_event_ids = replace_fqns_in_snapshot_hash(current_event_id_numbers) { |fqn|
|
104
102
|
fqn == 'current_event_id' ? fqn : (yield fqn)
|
105
103
|
}
|
106
104
|
|
107
|
-
|
105
|
+
logger.debug "Updating snapshot tables in redis"
|
106
|
+
replace_snapshot_tables(updated_event_ids, updated_events)
|
107
|
+
end
|
108
|
+
|
109
|
+
def reject!(logger = default_logger)
|
110
|
+
events_to_keep = read_with_rebuild(logger)
|
111
|
+
event_ids = current_event_id_numbers
|
112
|
+
|
113
|
+
events_to_keep.dup.each { |snapshot_key, snapshot_event|
|
114
|
+
serialized_event = serialized_event_from_snapshot_event(snapshot_key, snapshot_event)
|
115
|
+
drop_it = yield serialized_event
|
116
|
+
|
117
|
+
if drop_it
|
118
|
+
events_to_keep.delete(snapshot_key)
|
119
|
+
event_ids.delete(snapshot_key)
|
120
|
+
end
|
121
|
+
}
|
122
|
+
|
123
|
+
replace_snapshot_tables(event_ids.flatten, events_to_keep.flatten)
|
108
124
|
end
|
109
125
|
|
110
126
|
private
|
111
127
|
|
128
|
+
def serialized_event_from_snapshot_event(snapshot_key, snapshot_value)
|
129
|
+
fully_qualified_name, _ = snapshot_key.split(EventStore::SNAPSHOT_KEY_DELIMITER)
|
130
|
+
raw_event = snapshot_value.split(EventStore::SNAPSHOT_DELIMITER)
|
131
|
+
event_id = raw_event.first.to_i
|
132
|
+
serialized_event = EventStore.unescape_bytea(raw_event[1])
|
133
|
+
occurred_at = Time.parse(raw_event.last)
|
134
|
+
|
135
|
+
SerializedEvent.new(fully_qualified_name, serialized_event, event_id, occurred_at)
|
136
|
+
end
|
137
|
+
|
112
138
|
def replace_fqns_in_snapshot_hash(snapshot_keyed_hash)
|
113
139
|
snapshot_keyed_hash.inject([]) { |memo, (snapshot_key, value)|
|
114
140
|
new_key = replace_fqn_in_snapshot_key(snapshot_key) { |fqn| yield fqn }
|
@@ -122,16 +148,21 @@ module EventStore
|
|
122
148
|
[new_fqn, sub_key].compact.join(EventStore::SNAPSHOT_KEY_DELIMITER)
|
123
149
|
end
|
124
150
|
|
125
|
-
|
126
|
-
def update_snapshot_tables(event_ids_array, events_array, replace: false)
|
151
|
+
def replace_snapshot_tables(event_ids_array, events_array)
|
127
152
|
@redis.multi do
|
128
|
-
|
129
|
-
|
130
|
-
@redis.del snapshot_table if replace
|
131
|
-
@redis.hmset(snapshot_table, events_array)
|
153
|
+
delete_snapshot!
|
154
|
+
update_snapshot_tables(event_ids_array, events_array)
|
132
155
|
end
|
133
156
|
end
|
134
157
|
|
158
|
+
# params are flattened hashes, i.e., [key1, val1, key2, val2, ...]
|
159
|
+
def update_snapshot_tables(event_ids_array, events_array)
|
160
|
+
return unless events_array.any?
|
161
|
+
|
162
|
+
@redis.hmset(snapshot_event_id_table, event_ids_array)
|
163
|
+
@redis.hmset(snapshot_table, events_array)
|
164
|
+
end
|
165
|
+
|
135
166
|
def default_logger
|
136
167
|
Logger.new('/dev/null')
|
137
168
|
end
|
data/lib/event_store/version.rb
CHANGED
@@ -23,66 +23,110 @@ module EventStore
|
|
23
23
|
end
|
24
24
|
|
25
25
|
context "with events in the stream" do
|
26
|
-
let(:client)
|
26
|
+
let(:client) { EventStore::Client.new(AGGREGATE_ID_TWO) }
|
27
|
+
let(:snapshot) { client.snapshot }
|
28
|
+
let(:events) { events_for(AGGREGATE_ID_TWO) }
|
27
29
|
|
28
|
-
before
|
29
|
-
expect(
|
30
|
-
client.append
|
31
|
-
|
30
|
+
before {
|
31
|
+
expect(snapshot.count).to eq(0)
|
32
|
+
client.append events
|
33
|
+
}
|
32
34
|
|
33
35
|
describe "#count" do
|
34
36
|
it "delegates to the snapshot hash" do
|
35
|
-
expect(
|
37
|
+
expect(snapshot.count).to eq(8)
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
41
|
describe "#update_fqns!" do
|
40
|
-
let(:original_events) {
|
42
|
+
let(:original_events) { snapshot.to_a }
|
41
43
|
|
42
44
|
it "replaces fully qualified names in the snapshot with the value of a block" do
|
43
|
-
|
45
|
+
snapshot.update_fqns! { |fqn|
|
44
46
|
fqn =~ /^(e[0-9])/ ? fqn.upcase : fqn
|
45
47
|
}
|
46
48
|
|
47
49
|
expected_snapshot_events = original_events.map { |serialized_event| serialized_event.fully_qualified_name.upcase }
|
48
|
-
expect(
|
50
|
+
expect(snapshot.map(&:fully_qualified_name).to_set).to eq(expected_snapshot_events.to_set)
|
49
51
|
end
|
50
52
|
|
51
53
|
it "does not affect the current event id" do
|
52
|
-
old_event_id =
|
54
|
+
old_event_id = snapshot.event_id
|
53
55
|
|
54
|
-
|
56
|
+
snapshot.update_fqns! { |fqn| fqn.upcase }
|
55
57
|
|
56
|
-
new_event_id =
|
58
|
+
new_event_id = snapshot.event_id
|
57
59
|
|
58
60
|
expect(new_event_id).to eq(old_event_id)
|
59
61
|
end
|
60
62
|
|
61
63
|
it "doesn't affect the fully qualified name when the block returns nil" do
|
62
64
|
old_fqns = original_events.map(&:fully_qualified_name)
|
63
|
-
|
65
|
+
snapshot.update_fqns! { |_fqn| nil }
|
66
|
+
|
67
|
+
expect(snapshot.map(&:fully_qualified_name).to_set).to eq(old_fqns.to_set)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#reject!" do
|
72
|
+
it "yields the serialized event to the block" do
|
73
|
+
snapshot.reject! { |serialized_event|
|
74
|
+
expect(events.map(&:fully_qualified_name)).to include(serialized_event.fully_qualified_name)
|
75
|
+
expect(events.map(&:serialized_event)).to include(serialized_event.serialized_event)
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
context "when the block returns true" do
|
80
|
+
before(:each) { snapshot.reject! { |serialized_event| serialized_event.fully_qualified_name == 'e1' } }
|
81
|
+
|
82
|
+
it "removes the event from the snapshot" do
|
83
|
+
expect(snapshot.map(&:fully_qualified_name)).not_to include('e1')
|
84
|
+
end
|
85
|
+
|
86
|
+
it "removes the event id from the snapshot" do
|
87
|
+
expect(snapshot.event_id_for('e1')).to eq(-1)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when the block returns false" do
|
92
|
+
before(:each) { snapshot.reject! { |serialized_event| serialized_event.fully_qualified_name != 'e1' } }
|
93
|
+
|
94
|
+
it "retains the event in the snapshot" do
|
95
|
+
expect(snapshot.map(&:fully_qualified_name)).to include('e1')
|
96
|
+
end
|
97
|
+
|
98
|
+
it "retains the event id in the snapshot" do
|
99
|
+
expect(snapshot.event_id_for('e1')).not_to eq(-1)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "when all events are rejected" do
|
104
|
+
before(:each) { snapshot.reject! { true } }
|
64
105
|
|
65
|
-
|
106
|
+
it "deletes the snapshot out of Redis" do
|
107
|
+
expect(EventStore.redis.keys(snapshot.snapshot_table).length).to eq(0)
|
108
|
+
expect(EventStore.redis.keys(snapshot.snapshot_event_id_table).length).to eq(0)
|
109
|
+
end
|
66
110
|
end
|
67
111
|
end
|
68
112
|
|
69
113
|
it "rebuilds a snapshot after it is deleted" do
|
70
|
-
snapshot =
|
114
|
+
snapshot = snapshot
|
71
115
|
client.delete_snapshot!
|
72
116
|
client.rebuild_snapshot!
|
73
|
-
expect(
|
117
|
+
expect(snapshot).to eq(snapshot)
|
74
118
|
end
|
75
119
|
|
76
120
|
it "automatically rebuilds the snapshot if events exist, but the snapshot is empty" do
|
77
|
-
snapshot =
|
121
|
+
snapshot = snapshot
|
78
122
|
client.delete_snapshot!
|
79
|
-
expect(
|
123
|
+
expect(snapshot).to eq(snapshot)
|
80
124
|
end
|
81
125
|
|
82
126
|
it "finds the most recent records for each type" do
|
83
127
|
expected_snapshot_events = %w{e3 e1 e2 e5 e4 e7 e8 e7} #sorted by version no
|
84
128
|
expected_snapshot = serialized_events(expected_snapshot_events)
|
85
|
-
actual_snapshot =
|
129
|
+
actual_snapshot = snapshot
|
86
130
|
|
87
131
|
expect(client.event_stream.count).to eq(15)
|
88
132
|
expect(actual_snapshot.map(&:fully_qualified_name)).to eq(expected_snapshot_events)
|
@@ -91,7 +135,7 @@ module EventStore
|
|
91
135
|
end
|
92
136
|
|
93
137
|
it "increments the version number of the snapshot when an event is appended" do
|
94
|
-
expect(
|
138
|
+
expect(snapshot.event_id).to eq(client.raw_event_stream.last[:id])
|
95
139
|
end
|
96
140
|
end
|
97
141
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nexia_event_store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Saieg, John Colvin
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-03-
|
12
|
+
date: 2016-03-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|