nexia_event_store 0.3.3 → 0.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
  SHA1:
3
- metadata.gz: 4d0343124beb0b58cbd89357ae7faefe2fddec53
4
- data.tar.gz: 77595f7c4826c2f732a4fb6cca2e6a955d751e5a
3
+ metadata.gz: a53b46ee6253d85453dc97abcaea3cf60d1b6cd6
4
+ data.tar.gz: 717b8827588f413f87b41513c2ef8539254140fb
5
5
  SHA512:
6
- metadata.gz: a2e7aee13bbb0afd22c5165a467071cabe04a045ebd246f6bcc8149a180ed4af2849e865c898e4734f7c9434b5eb4e90eaf1c7e715f5361a7e241f4fc0b0a20b
7
- data.tar.gz: 99586d4de51eaad607c346b6776183e85304cc4d4fa7b01544d20b37c49f002b2c368c52a5dd04edd439725ca04c152d57d8dcb38791f8d636ce8f06eb13e2d6
6
+ metadata.gz: b96e05c1a31be2b889a473e86ea7254f506d946be4ef505d6fb2522a3b6c23a425cdc3a0debd3b3ba73d9e0eae386e06e71f4378735a09fc64dd6e452f516971
7
+ data.tar.gz: 8e2ecbf2ca66a91042dda7fd790f2b61f328a432232045c27b16d1d8fa5807a8a123033345fee46718c65a2a5e5ec7e4c0d6693e945f1dd43e1ee6233f8cdc1c
@@ -22,6 +22,10 @@ module EventStore
22
22
  :event_table,
23
23
  :delete_events!
24
24
 
25
+ def snapshot_exists?
26
+ @snapshot.exists?
27
+ end
28
+
25
29
  def self.count
26
30
  EventStore.db.from( EventStore.fully_qualified_table).distinct(:aggregate_id).count
27
31
  end
@@ -2,7 +2,7 @@ module EventStore
2
2
  class Client
3
3
  extend Forwardable
4
4
 
5
- def_delegators :@aggregate, :delete_snapshot!, :snapshot_version_table
5
+ def_delegators :aggregate, :delete_snapshot!, :snapshot_version_table
6
6
 
7
7
  def self.count
8
8
  Aggregate.count
@@ -16,20 +16,24 @@ module EventStore
16
16
  @aggregate = Aggregate.new(aggregate_id, aggregate_type)
17
17
  end
18
18
 
19
+ def exists?
20
+ aggregate.snapshot_exists?
21
+ end
22
+
19
23
  def id
20
- @aggregate.id
24
+ aggregate.id
21
25
  end
22
26
 
23
27
  def type
24
- @aggregate.type
28
+ aggregate.type
25
29
  end
26
30
 
27
31
  def event_table
28
- @aggregate.event_table
32
+ aggregate.event_table
29
33
  end
30
34
 
31
35
  def append(event_data)
32
- @aggregate.append(event_data)
36
+ aggregate.append(event_data)
33
37
  yield(event_data) if block_given?
34
38
  nil
35
39
  end
@@ -43,31 +47,31 @@ module EventStore
43
47
  end
44
48
 
45
49
  def event_stream_from(version_number, max=nil)
46
- translate_events(@aggregate.events_from(version_number, max))
50
+ translate_events(aggregate.events_from(version_number, max))
47
51
  end
48
52
 
49
53
  def event_stream_between(start_time, end_time, fully_qualified_names = [])
50
- translate_events(@aggregate.event_stream_between(start_time, end_time, fully_qualified_names))
54
+ translate_events(aggregate.event_stream_between(start_time, end_time, fully_qualified_names))
51
55
  end
52
56
 
53
57
  def peek
54
- @aggregate.last_event
58
+ aggregate.last_event
55
59
  end
56
60
 
57
61
  def raw_snapshot
58
- @aggregate.snapshot
62
+ aggregate.snapshot
59
63
  end
60
64
 
61
65
  def raw_event_stream
62
- @aggregate.event_stream
66
+ aggregate.event_stream
63
67
  end
64
68
 
65
69
  def raw_event_stream_from version_number, max=nil
66
- @aggregate.events_from(version_number, max)
70
+ aggregate.events_from(version_number, max)
67
71
  end
68
72
 
69
73
  def version
70
- @aggregate.version
74
+ aggregate.version
71
75
  end
72
76
 
73
77
  def count
@@ -75,17 +79,19 @@ module EventStore
75
79
  end
76
80
 
77
81
  def destroy!
78
- @aggregate.delete_events!
79
- @aggregate.delete_snapshot!
82
+ aggregate.delete_events!
83
+ aggregate.delete_snapshot!
80
84
  end
81
85
 
82
86
  def rebuild_snapshot!
83
- @aggregate.delete_snapshot!
84
- @aggregate.rebuild_snapshot!
87
+ aggregate.delete_snapshot!
88
+ aggregate.rebuild_snapshot!
85
89
  end
86
90
 
87
91
  private
88
92
 
93
+ attr_reader :aggregate
94
+
89
95
  def translate_events(event_hashs)
90
96
  event_hashs.map { |eh| translate_event(eh) }
91
97
  end
@@ -1,7 +1,7 @@
1
1
  module EventStore
2
2
  class Snapshot
3
3
 
4
- attr_reader :snapshot_version_table
4
+ attr_reader :snapshot_version_table, :snapshot_table
5
5
 
6
6
  def initialize aggregate
7
7
  @aggregate = aggregate
@@ -10,12 +10,20 @@ module EventStore
10
10
  @snapshot_version_table = "#{@aggregate.type}_snapshot_versions_for_#{@aggregate.id}"
11
11
  end
12
12
 
13
+ def exists?
14
+ @redis.exists(snapshot_table)
15
+ end
16
+
13
17
  def last_event
14
18
  snapshot.last
15
19
  end
16
20
 
17
21
  def version
18
- (@redis.hget(@snapshot_version_table, :current_version) || -1).to_i
22
+ (@redis.hget(snapshot_version_table, :current_version) || -1).to_i
23
+ end
24
+
25
+ def size
26
+ snapshot.size
19
27
  end
20
28
 
21
29
  def snapshot
@@ -39,7 +47,7 @@ module EventStore
39
47
  end
40
48
 
41
49
  def delete_snapshot!
42
- EventStore.redis.del [@snapshot_table, @snapshot_version_table]
50
+ EventStore.redis.del [snapshot_table, snapshot_version_table]
43
51
  end
44
52
 
45
53
  def store_snapshot(prepared_events)
@@ -57,8 +65,8 @@ module EventStore
57
65
  valid_snapshot_versions += [:current_version, valid_snapshot_versions.last.to_i]
58
66
 
59
67
  @redis.multi do
60
- @redis.hmset(@snapshot_version_table, valid_snapshot_versions)
61
- @redis.hmset(@snapshot_table, valid_snapshot_events)
68
+ @redis.hmset(snapshot_version_table, valid_snapshot_versions)
69
+ @redis.hmset(snapshot_table, valid_snapshot_events)
62
70
  end
63
71
  end
64
72
  end
@@ -87,13 +95,13 @@ module EventStore
87
95
  end
88
96
 
89
97
  def current_version_numbers
90
- current_versions = @redis.hgetall(@snapshot_version_table)
98
+ current_versions = @redis.hgetall(snapshot_version_table)
91
99
  current_versions.default = -1
92
100
  current_versions
93
101
  end
94
102
 
95
103
  def read_raw_snapshot
96
- @redis.hgetall(@snapshot_table)
104
+ @redis.hgetall(snapshot_table)
97
105
  end
98
106
 
99
107
  def auto_rebuild_snapshot(events_hash)
@@ -1,3 +1,3 @@
1
1
  module EventStore
2
- VERSION = '0.3.3'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -6,7 +6,7 @@ AGGREGATE_ID_TWO = SecureRandom.uuid
6
6
  AGGREGATE_ID_THREE = SecureRandom.uuid
7
7
 
8
8
  describe EventStore::Client do
9
- let(:es_client) { EventStore::Client }
9
+ subject(:es_client) { EventStore::Client }
10
10
 
11
11
  before do
12
12
  client_1 = es_client.new(AGGREGATE_ID_ONE, :device)
@@ -33,6 +33,19 @@ describe EventStore::Client do
33
33
  expect(es_client.ids(offset, limit)).to eq([[AGGREGATE_ID_ONE, AGGREGATE_ID_TWO].sort.first])
34
34
  end
35
35
 
36
+ describe "#exists?" do
37
+ let(:fake_aggregate) { double("Aggregate") }
38
+
39
+ subject(:client) { es_client.new(AGGREGATE_ID_ONE, :device) }
40
+
41
+ before(:each) { expect(client).to receive(:aggregate).and_return(fake_aggregate) }
42
+
43
+ it "checks if the snapshot exists" do
44
+ expect(fake_aggregate).to receive(:snapshot_exists?).and_return(true)
45
+ expect(client.exists?).to eq(true)
46
+ end
47
+ end
48
+
36
49
  describe '#raw_event_stream' do
37
50
  it "should be an array of hashes that represent database records, not EventStore::SerializedEvent objects" do
38
51
  raw_stream = es_client.new(AGGREGATE_ID_ONE, :device).raw_event_stream
@@ -373,10 +386,12 @@ describe EventStore::Client do
373
386
  end
374
387
 
375
388
  end
389
+
376
390
  def serialized_event_data_terminated_by_null
377
391
  @term_data ||= File.open(File.expand_path("../binary_string_term_with_null_byte.txt", __FILE__), 'rb') {|f| f.read}
378
392
  @term_data
379
393
  end
394
+
380
395
  def serialized_binary_event_data
381
396
  @event_data ||= File.open(File.expand_path("../serialized_binary_event_data.txt", __FILE__), 'rb') {|f| f.read}
382
397
  @event_data
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'mock_redis'
3
+
4
+ module EventStore
5
+ describe Aggregate do
6
+ let(:aggregate_id) { "014001A8" }
7
+ let(:type) { "fake_events" }
8
+ let(:fake_snapshot) { double("Snapshot", exists?: true) }
9
+ let(:fake_stream) { double("EventStream") }
10
+
11
+ before(:each) { allow(Snapshot).to receive(:new).and_return(fake_snapshot) }
12
+ before(:each) { allow(EventStream).to receive(:new).and_return(fake_stream) }
13
+
14
+ subject(:aggregate) { EventStore::Aggregate.new(aggregate_id, type) }
15
+
16
+ describe "#count" do
17
+ it "has tests"
18
+ end
19
+
20
+ describe "#ids" do
21
+ it "has tests"
22
+ end
23
+
24
+ describe "#append" do
25
+ it "has tests"
26
+ end
27
+
28
+ describe "#snapshot_exists?" do
29
+ it "delegates to its snapshot" do
30
+ expect(fake_snapshot).to receive(:exists?).and_return(true)
31
+ expect(aggregate.snapshot_exists?).to eq(true)
32
+ end
33
+
34
+ it "does not build a snapshot" do
35
+ expect(fake_snapshot).to_not receive(:snapshot) # :(
36
+ aggregate.snapshot_exists?
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+ require 'mock_redis'
3
+
4
+ module EventStore
5
+ describe Snapshot do
6
+ let(:redis) { EventStore.redis }
7
+ let(:aggregate_type) { "awesome" }
8
+ let(:aggregate_id) { "superman" }
9
+ let(:events) { [] }
10
+ let(:aggregate) { double("Aggregate", type: aggregate_type, id: aggregate_id, events: double(all: events)) }
11
+
12
+ subject(:snapshot) { EventStore::Snapshot.new(aggregate) }
13
+
14
+ it "has a version table for the snapshot" do
15
+ expect(snapshot.snapshot_version_table).to eq "#{aggregate_type}_snapshot_versions_for_#{aggregate_id}"
16
+ end
17
+
18
+ context "with events in the snapshot table" do
19
+ let(:first_event) {
20
+ { version: 1,
21
+ fully_qualified_name: "fqn",
22
+ sub_key: "sub",
23
+ serialized_event: EventStore.escape_bytea("cheerios"),
24
+ occurred_at: Time.at( (Time.now - 3600).to_i )
25
+ }
26
+ }
27
+ let(:last_event) {
28
+ { version: 2,
29
+ fully_qualified_name: "fqn2",
30
+ sub_key: "sub2",
31
+ serialized_event: EventStore.escape_bytea("cheerios2"),
32
+ occurred_at: Time.at( (Time.now - 1800).to_i )
33
+ }
34
+ }
35
+ let(:events) { [ first_event, last_event ] }
36
+
37
+ before(:each) { snapshot.store_snapshot(events) }
38
+
39
+ describe "#last_event" do
40
+ let(:events) { [ last_event, first_event ] }
41
+
42
+ it "returns the event with the highest version" do
43
+ expect(snapshot.last_event.fully_qualified_name).to eq(last_event[:fully_qualified_name])
44
+ end
45
+ end
46
+
47
+ describe "#version" do
48
+ it "is the highest version of the last inserted event in the snapshot" do
49
+ expect(snapshot.version).to eq(last_event[:version])
50
+ end
51
+ end
52
+
53
+ describe "#rebuild_snapshot!" do
54
+ it "deletes the existing snapshot" do
55
+ expect(redis).to receive(:del).with([snapshot.snapshot_table , snapshot.snapshot_version_table])
56
+ snapshot.rebuild_snapshot!
57
+ end
58
+
59
+ it "stores a a new snapshot from the aggregate's events" do
60
+ snapshot.rebuild_snapshot!
61
+ expect(snapshot.size).to eq(2)
62
+ # TODO: remove #snapshot in favor of Enumerable
63
+ names = snapshot.snapshot.map(&:fully_qualified_name)
64
+ expect(names).to eq(events.map { |e| e[:fully_qualified_name] })
65
+ end
66
+ end
67
+
68
+ # TODO: remove this in favor of #each and include Enumerable
69
+ describe "#snapshot" do
70
+ let(:event_snapshot) { snapshot.snapshot }
71
+ let(:serialized_attrs) { [ :fully_qualified_name,
72
+ :serialized_event,
73
+ :version,
74
+ :occurred_at ] }
75
+
76
+ it "contains SerializedEvents" do
77
+ event_snapshot.each { |e| expect(e).to be_a(SerializedEvent) }
78
+ end
79
+
80
+ it "corresponds to the events used to build the snapshot" do
81
+ (serialized_attrs - [ :serialized_event ]).each { |attr|
82
+ expect(event_snapshot.first.send(attr)).to eq(first_event[attr])
83
+ expect(event_snapshot.last.send(attr)).to eq(last_event[attr])
84
+ }
85
+ end
86
+
87
+ it "unescapes the serialized events" do
88
+ expected_event = EventStore.unescape_bytea(last_event[:serialized_event])
89
+ expect(event_snapshot.last.serialized_event).to eq(expected_event)
90
+ end
91
+ end
92
+
93
+ describe "#exists?" do
94
+ it "does exist" do
95
+ expect(snapshot.exists?).to eq(true)
96
+ end
97
+
98
+ context "without a snapshot" do
99
+ before(:each) { snapshot.delete_snapshot! }
100
+
101
+ it "does not exist" do
102
+ expect(snapshot.exists?).to eq(false)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
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.3.3
4
+ version: 0.4.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: 2014-12-17 00:00:00.000000000 Z
12
+ date: 2015-01-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -251,6 +251,8 @@ files:
251
251
  - spec/event_store/snapshot_spec.rb
252
252
  - spec/event_store/vertica guy notes.txt
253
253
  - spec/spec_helper.rb
254
+ - spec/unit/aggregate_unit_spec.rb
255
+ - spec/unit/snapshot_unit_spec.rb
254
256
  homepage: https://github.com/nexiahome/event_store
255
257
  licenses:
256
258
  - MIT
@@ -271,7 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
271
273
  version: '0'
272
274
  requirements: []
273
275
  rubyforge_project:
274
- rubygems_version: 2.4.2
276
+ rubygems_version: 2.4.5
275
277
  signing_key:
276
278
  specification_version: 4
277
279
  summary: Ruby implementation of an EventSource (A+ES) for the Nexia Ecosystem
@@ -286,3 +288,5 @@ test_files:
286
288
  - spec/event_store/snapshot_spec.rb
287
289
  - spec/event_store/vertica guy notes.txt
288
290
  - spec/spec_helper.rb
291
+ - spec/unit/aggregate_unit_spec.rb
292
+ - spec/unit/snapshot_unit_spec.rb