evt-message_store 0.1.0.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 +7 -0
- data/lib/message_store.rb +25 -0
- data/lib/message_store/controls.rb +18 -0
- data/lib/message_store/controls/category.rb +23 -0
- data/lib/message_store/controls/get.rb +25 -0
- data/lib/message_store/controls/id.rb +11 -0
- data/lib/message_store/controls/iterator.rb +26 -0
- data/lib/message_store/controls/message_data.rb +17 -0
- data/lib/message_store/controls/message_data/hash.rb +28 -0
- data/lib/message_store/controls/message_data/metadata.rb +24 -0
- data/lib/message_store/controls/message_data/read.rb +74 -0
- data/lib/message_store/controls/message_data/write.rb +54 -0
- data/lib/message_store/controls/random_value.rb +9 -0
- data/lib/message_store/controls/read.rb +16 -0
- data/lib/message_store/controls/stream_name.rb +29 -0
- data/lib/message_store/controls/time.rb +60 -0
- data/lib/message_store/controls/write.rb +23 -0
- data/lib/message_store/expected_version.rb +11 -0
- data/lib/message_store/get.rb +65 -0
- data/lib/message_store/log.rb +9 -0
- data/lib/message_store/message_data.rb +18 -0
- data/lib/message_store/message_data/hash.rb +31 -0
- data/lib/message_store/message_data/read.rb +12 -0
- data/lib/message_store/message_data/write.rb +7 -0
- data/lib/message_store/no_stream.rb +11 -0
- data/lib/message_store/read.rb +76 -0
- data/lib/message_store/read/iterator.rb +143 -0
- data/lib/message_store/stream_name.rb +50 -0
- data/lib/message_store/write.rb +66 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cbb27c84708165c4c45115a2c898b13c961ac316
|
4
|
+
data.tar.gz: 5903ed1eaccc4ecd8887a29892ddeff5f9919f33
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 222bf221662fb048aa8c9bfc19f3e83781eaae32e6fc64e8b18eebb38e7af5361db242ff1de48bd99d3aa49dd62c6f4e891c5e5d4da9f37c4160c689b955344e
|
7
|
+
data.tar.gz: 1381711997c88044b183228967802ce5825b4c819b291d6e632de9e49b060475ec12562cc9c6a7f95feaff2aa3617d1ec077d3083c9c70a92aeb9c95397b1838
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require 'casing'
|
5
|
+
require 'identifier/uuid'
|
6
|
+
require 'schema'
|
7
|
+
require 'initializer'; Initializer.activate
|
8
|
+
require 'transform'
|
9
|
+
require 'virtual'; Virtual.activate
|
10
|
+
require 'async_invocation'
|
11
|
+
|
12
|
+
require 'message_store/expected_version'
|
13
|
+
require 'message_store/no_stream'
|
14
|
+
require 'message_store/message_data'
|
15
|
+
require 'message_store/message_data/hash'
|
16
|
+
require 'message_store/message_data/write'
|
17
|
+
require 'message_store/message_data/read'
|
18
|
+
require 'message_store/stream_name'
|
19
|
+
|
20
|
+
require 'message_store/log'
|
21
|
+
|
22
|
+
require 'message_store/get'
|
23
|
+
require 'message_store/read/iterator'
|
24
|
+
require 'message_store/read'
|
25
|
+
require 'message_store/write'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
require 'identifier/uuid/controls'
|
4
|
+
|
5
|
+
require 'message_store/controls/random_value'
|
6
|
+
require 'message_store/controls/time'
|
7
|
+
require 'message_store/controls/id'
|
8
|
+
require 'message_store/controls/category'
|
9
|
+
require 'message_store/controls/stream_name'
|
10
|
+
require 'message_store/controls/read'
|
11
|
+
require 'message_store/controls/message_data'
|
12
|
+
require 'message_store/controls/message_data/hash'
|
13
|
+
require 'message_store/controls/message_data/metadata'
|
14
|
+
require 'message_store/controls/message_data/write'
|
15
|
+
require 'message_store/controls/message_data/read'
|
16
|
+
require 'message_store/controls/write'
|
17
|
+
require 'message_store/controls/get'
|
18
|
+
require 'message_store/controls/iterator'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module Category
|
4
|
+
def self.example(category: nil, randomize_category: nil)
|
5
|
+
if randomize_category.nil?
|
6
|
+
if !category.nil?
|
7
|
+
randomize_category = false
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
randomize_category = true if randomize_category.nil?
|
12
|
+
|
13
|
+
category ||= 'test'
|
14
|
+
|
15
|
+
if randomize_category
|
16
|
+
category = "#{category}#{SecureRandom.hex(16)}XX"
|
17
|
+
end
|
18
|
+
|
19
|
+
category
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module Get
|
4
|
+
def self.example(batch_size: nil, count: nil, global_position_offset: nil)
|
5
|
+
batch_size ||= 1
|
6
|
+
count ||= 1
|
7
|
+
global_position_offset ||= -> (x) { x ** 2 }
|
8
|
+
|
9
|
+
get = MessageStore::Get::Substitute.build(batch_size: batch_size)
|
10
|
+
|
11
|
+
elements = (0..(count - 1)).to_a
|
12
|
+
|
13
|
+
elements.each do |e|
|
14
|
+
message_data = MessageData::Read.example
|
15
|
+
message_data.position = e
|
16
|
+
message_data.global_position = global_position_offset.(message_data.position)
|
17
|
+
|
18
|
+
get.items << message_data
|
19
|
+
end
|
20
|
+
|
21
|
+
get
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module ID
|
4
|
+
def self.example(i=nil, increment: nil, sample: nil)
|
5
|
+
Identifier::UUID::Controls::Incrementing.example(i=nil, increment: nil, sample: nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
Random = Identifier::UUID::Controls::Random
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module Iterator
|
4
|
+
def self.example(stream_name: nil, position: nil)
|
5
|
+
stream_name ||= StreamName.example
|
6
|
+
Example.build(stream_name, position: position)
|
7
|
+
end
|
8
|
+
|
9
|
+
class Example
|
10
|
+
include MessageStore::Read::Iterator
|
11
|
+
|
12
|
+
def last_position
|
13
|
+
unless self.class.category?(stream_name)
|
14
|
+
batch.last.position
|
15
|
+
else
|
16
|
+
batch.last.global_position
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.category?(stream_name)
|
21
|
+
!stream_name.include?('-')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module MessageData
|
4
|
+
module Hash
|
5
|
+
def self.data
|
6
|
+
{
|
7
|
+
some_attribute: 'some value'
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.example
|
12
|
+
MessageStore::MessageData::Hash[data]
|
13
|
+
end
|
14
|
+
|
15
|
+
module JSON
|
16
|
+
def self.data(id=nil)
|
17
|
+
data = Hash.data
|
18
|
+
Casing::Camel.(data, symbol_to_string: true)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.text
|
22
|
+
::JSON.generate(data)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module MessageData
|
4
|
+
module Metadata
|
5
|
+
def self.data
|
6
|
+
{
|
7
|
+
meta_attribute: RandomValue.example
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
module JSON
|
12
|
+
def self.data(id=nil)
|
13
|
+
data = Metadata.data
|
14
|
+
Casing::Camel.(data, symbol_to_string: true)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.text
|
18
|
+
data.to_json
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module MessageData
|
4
|
+
module Read
|
5
|
+
def self.example(id: nil, type: nil, data: nil, metadata: nil)
|
6
|
+
if id == :none
|
7
|
+
id = nil
|
8
|
+
else
|
9
|
+
id ||= self.id
|
10
|
+
end
|
11
|
+
|
12
|
+
type ||= self.type
|
13
|
+
|
14
|
+
if data == :none
|
15
|
+
data = nil
|
16
|
+
else
|
17
|
+
data ||= self.data
|
18
|
+
end
|
19
|
+
|
20
|
+
if metadata == :none
|
21
|
+
metadata = nil
|
22
|
+
else
|
23
|
+
metadata ||= self.metadata
|
24
|
+
end
|
25
|
+
|
26
|
+
message_data = MessageStore::MessageData::Read.build
|
27
|
+
|
28
|
+
message_data.id = id
|
29
|
+
message_data.type = type
|
30
|
+
message_data.data = data
|
31
|
+
message_data.metadata = metadata
|
32
|
+
message_data.position = position
|
33
|
+
message_data.global_position = global_position
|
34
|
+
message_data.time = time
|
35
|
+
message_data.stream_name = stream_name
|
36
|
+
|
37
|
+
message_data
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.id
|
41
|
+
MessageData.id
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.type
|
45
|
+
MessageData.type
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.data
|
49
|
+
MessageData.data
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.metadata
|
53
|
+
MessageData::Metadata.data
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.position
|
57
|
+
1
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.global_position
|
61
|
+
111
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.time
|
65
|
+
Time::Raw.example
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.stream_name
|
69
|
+
StreamName.example
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module MessageData
|
4
|
+
module Write
|
5
|
+
def self.example(id: nil, type: nil, data: nil, metadata: nil)
|
6
|
+
if id == :none
|
7
|
+
id = nil
|
8
|
+
else
|
9
|
+
id ||= self.id
|
10
|
+
end
|
11
|
+
|
12
|
+
type ||= self.type
|
13
|
+
|
14
|
+
if data == :none
|
15
|
+
data = nil
|
16
|
+
else
|
17
|
+
data ||= self.data
|
18
|
+
end
|
19
|
+
|
20
|
+
if metadata == :none
|
21
|
+
metadata = nil
|
22
|
+
else
|
23
|
+
metadata ||= self.metadata
|
24
|
+
end
|
25
|
+
|
26
|
+
message_data = MessageStore::MessageData::Write.build
|
27
|
+
|
28
|
+
message_data.id = id
|
29
|
+
message_data.type = type
|
30
|
+
message_data.data = data
|
31
|
+
message_data.metadata = metadata
|
32
|
+
|
33
|
+
message_data
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.id
|
37
|
+
MessageData.id
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.type
|
41
|
+
MessageData.type
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.data
|
45
|
+
MessageData.data
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.metadata
|
49
|
+
MessageData::Metadata.data
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module Read
|
4
|
+
def self.example(stream_name: nil)
|
5
|
+
stream_name ||= StreamName.example
|
6
|
+
Example.build(stream_name)
|
7
|
+
end
|
8
|
+
|
9
|
+
class Example
|
10
|
+
include MessageStore::Read
|
11
|
+
|
12
|
+
def configure(*); end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module StreamName
|
4
|
+
def self.example(category: nil, id: nil, type: nil, types: nil, randomize_category: nil)
|
5
|
+
category ||= Category.example(category: category, randomize_category: randomize_category)
|
6
|
+
id ||= Identifier::UUID.random
|
7
|
+
|
8
|
+
stream_name(category, id, type: type, types: types)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.stream_name(category_name, id=nil, type: nil, types: nil)
|
12
|
+
types = Array(types)
|
13
|
+
types.unshift(type) unless type.nil?
|
14
|
+
|
15
|
+
type_list = nil
|
16
|
+
type_list = types.join('+') unless types.empty?
|
17
|
+
|
18
|
+
stream_name = category_name
|
19
|
+
stream_name = "#{stream_name}:#{type_list}" unless type_list.nil?
|
20
|
+
stream_name = "#{stream_name}-#{id}" unless id.nil?
|
21
|
+
|
22
|
+
stream_name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module Time
|
4
|
+
def self.example(time=nil)
|
5
|
+
time ||= Raw.example
|
6
|
+
ISO8601.example(time)
|
7
|
+
end
|
8
|
+
|
9
|
+
module Raw
|
10
|
+
def self.example
|
11
|
+
time = ::Time.parse("Jan 1 00:00:00 UTC 2000")
|
12
|
+
Clock::UTC.now(time)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ISO8601
|
17
|
+
def self.example(time=nil)
|
18
|
+
time ||= Raw.example
|
19
|
+
Clock::UTC.iso8601(time)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Processed
|
24
|
+
def self.example(time=nil, offset_milliseconds: nil)
|
25
|
+
time ||= Time::Raw.example
|
26
|
+
time = Raw.example(time, offset_milliseconds: offset_milliseconds)
|
27
|
+
ISO8601.example(time)
|
28
|
+
end
|
29
|
+
|
30
|
+
module Raw
|
31
|
+
def self.example(time=nil, offset_milliseconds: nil)
|
32
|
+
time ||= Time::Raw.example
|
33
|
+
offset_milliseconds ||= 11
|
34
|
+
offset = Rational(offset_milliseconds, 1000)
|
35
|
+
time += offset
|
36
|
+
time
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Effective
|
42
|
+
def self.example(time=nil, offset_milliseconds: nil)
|
43
|
+
time ||= Time::Raw.example
|
44
|
+
time = Raw.example(time, offset_milliseconds: offset_milliseconds)
|
45
|
+
ISO8601.example(time)
|
46
|
+
end
|
47
|
+
|
48
|
+
module Raw
|
49
|
+
def self.example(time=nil, offset_milliseconds: nil)
|
50
|
+
time ||= Time::Raw.example
|
51
|
+
offset_milliseconds ||= 1
|
52
|
+
offset = Rational(offset_milliseconds, 1000)
|
53
|
+
time += offset
|
54
|
+
time
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Controls
|
3
|
+
module Write
|
4
|
+
def self.example
|
5
|
+
Example.build
|
6
|
+
end
|
7
|
+
|
8
|
+
class Example
|
9
|
+
include MessageStore::Write
|
10
|
+
|
11
|
+
def configure(*)
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(batch, stream_name, expected_version: nil)
|
15
|
+
logger.trace { "Writing batch (Stream Name: #{stream_name}, Number of Events: #{batch.length}, Expected Version: #{expected_version.inspect})" }
|
16
|
+
logger.debug { "Wrote batch (Stream Name: #{stream_name}, Number of Events: #{batch.length}, Expected Version: #{expected_version.inspect})" }
|
17
|
+
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module ExpectedVersion
|
3
|
+
class Error < RuntimeError; end
|
4
|
+
|
5
|
+
def self.canonize(expected_version)
|
6
|
+
return nil if expected_version.nil?
|
7
|
+
return expected_version unless expected_version == NoStream.name
|
8
|
+
NoStream.version
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Get
|
3
|
+
def self.included(cls)
|
4
|
+
cls.class_exec do
|
5
|
+
include Log::Dependency
|
6
|
+
|
7
|
+
abstract :call
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Substitute
|
12
|
+
include Get
|
13
|
+
|
14
|
+
initializer na(:batch_size)
|
15
|
+
|
16
|
+
def batch_size
|
17
|
+
@batch_size ||= 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def items
|
21
|
+
@items ||= []
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.build(batch_size: nil, session: nil)
|
25
|
+
new(batch_size)
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(stream_name=nil, position: nil)
|
29
|
+
position ||= 0
|
30
|
+
|
31
|
+
logger.trace(tag: :control) { "Getting (Position: #{position}, Batch Size: #{batch_size}, Stream Name: #{stream_name.inspect})" }
|
32
|
+
|
33
|
+
logger.debug(tags: [:control, :data]) { "Items: \n#{items.pretty_inspect}" }
|
34
|
+
logger.debug(tag: :control) { "Position: #{position.inspect}" }
|
35
|
+
logger.debug(tag: :control) { "Batch Size: #{batch_size.inspect}" }
|
36
|
+
|
37
|
+
unless self.class.category?(stream_name)
|
38
|
+
index = (items.index { |i| i.position >= position })
|
39
|
+
else
|
40
|
+
index = (items.index { |i| i.global_position >= position })
|
41
|
+
end
|
42
|
+
|
43
|
+
logger.debug(tag: :control) { "Index: #{index.inspect}" }
|
44
|
+
|
45
|
+
if index.nil?
|
46
|
+
items = []
|
47
|
+
else
|
48
|
+
range = index..(index + batch_size - 1)
|
49
|
+
logger.debug(tag: :control) { "Range: #{range.pretty_inspect}" }
|
50
|
+
|
51
|
+
items = self.items[range]
|
52
|
+
end
|
53
|
+
|
54
|
+
logger.info(tags: [:control, :data]) { "Got: \n#{items.pretty_inspect}" }
|
55
|
+
logger.info(tag: :control) { "Finished getting (Position: #{position}, Stream Name: #{stream_name.inspect})" }
|
56
|
+
|
57
|
+
items
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.category?(stream_name)
|
61
|
+
!stream_name.include?('-')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module MessageData
|
3
|
+
def self.included(cls)
|
4
|
+
cls.class_exec do
|
5
|
+
include Schema::DataStructure
|
6
|
+
|
7
|
+
attribute :id, String
|
8
|
+
attribute :type, String
|
9
|
+
attribute :data
|
10
|
+
attribute :metadata
|
11
|
+
|
12
|
+
def ===(other)
|
13
|
+
type == other
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module MessageData
|
3
|
+
class Hash < ::Hash
|
4
|
+
module Transformer
|
5
|
+
def self.json
|
6
|
+
JSON
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.instance(raw_data)
|
10
|
+
Hash[raw_data]
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.raw_data(instance)
|
14
|
+
Hash[instance]
|
15
|
+
end
|
16
|
+
|
17
|
+
module JSON
|
18
|
+
def self.write(raw_hash_data)
|
19
|
+
json_formatted_data = Casing::Camel.(raw_hash_data)
|
20
|
+
::JSON.generate(json_formatted_data)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.read(text)
|
24
|
+
json_formatted_data = ::JSON.parse(text, :symbolize_names => true)
|
25
|
+
Casing::Underscore.(json_formatted_data)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Read
|
3
|
+
def self.included(cls)
|
4
|
+
cls.class_exec do
|
5
|
+
include Log::Dependency
|
6
|
+
|
7
|
+
cls.extend Build
|
8
|
+
cls.extend Call
|
9
|
+
cls.extend Configure
|
10
|
+
|
11
|
+
dependency :iterator, Iterator
|
12
|
+
|
13
|
+
initializer :stream_name, :position, :batch_size
|
14
|
+
|
15
|
+
abstract :configure
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Error < RuntimeError; end
|
20
|
+
|
21
|
+
module Build
|
22
|
+
def build(stream_name, position: nil, batch_size: nil, session: nil)
|
23
|
+
new(stream_name, position, batch_size).tap do |instance|
|
24
|
+
instance.configure(session: session)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module Call
|
30
|
+
def call(stream_name, position: nil, batch_size: nil, session: nil, &action)
|
31
|
+
instance = build(stream_name, position: position, batch_size: batch_size, session: session)
|
32
|
+
instance.(&action)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Configure
|
37
|
+
def configure(receiver, stream_name, attr_name: nil, position: nil, batch_size: nil, session: nil)
|
38
|
+
attr_name ||= :read
|
39
|
+
instance = build(stream_name, position: position, batch_size: batch_size, session: session)
|
40
|
+
receiver.public_send "#{attr_name}=", instance
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def call(&action)
|
45
|
+
logger.trace { "Reading (Stream Name: #{stream_name})" }
|
46
|
+
|
47
|
+
if action.nil?
|
48
|
+
error_message = "Reader must be actuated with a block"
|
49
|
+
logger.error error_message
|
50
|
+
raise Error, error_message
|
51
|
+
end
|
52
|
+
|
53
|
+
enumerate_message_data(&action)
|
54
|
+
|
55
|
+
logger.info { "Reading completed (Stream Name: #{stream_name})" }
|
56
|
+
|
57
|
+
return AsyncInvocation::Incorrect
|
58
|
+
end
|
59
|
+
|
60
|
+
def enumerate_message_data(&action)
|
61
|
+
logger.trace { "Enumerating (Stream Name: #{stream_name})" }
|
62
|
+
|
63
|
+
message_data = nil
|
64
|
+
|
65
|
+
loop do
|
66
|
+
message_data = iterator.next
|
67
|
+
|
68
|
+
break if message_data.nil?
|
69
|
+
|
70
|
+
action.(message_data)
|
71
|
+
end
|
72
|
+
|
73
|
+
logger.debug { "Enumerated (Stream Name: #{stream_name})" }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Read
|
3
|
+
module Iterator
|
4
|
+
def self.included(cls)
|
5
|
+
cls.class_exec do
|
6
|
+
cls.extend Build
|
7
|
+
cls.extend Configure
|
8
|
+
|
9
|
+
include Log::Dependency
|
10
|
+
|
11
|
+
dependency :get, Get
|
12
|
+
|
13
|
+
initializer :stream_name
|
14
|
+
|
15
|
+
abstract :last_position
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :starting_position
|
20
|
+
attr_accessor :batch
|
21
|
+
|
22
|
+
def batch_index
|
23
|
+
@batch_index ||= 0
|
24
|
+
end
|
25
|
+
attr_writer :batch_index
|
26
|
+
|
27
|
+
module Build
|
28
|
+
def build(stream_name, position: nil)
|
29
|
+
new(stream_name).tap do |instance|
|
30
|
+
instance.starting_position = position
|
31
|
+
Log.get(self).debug { "Built Iterator (Stream Name: #{stream_name}, Starting Position: #{position.inspect})" }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Configure
|
37
|
+
def configure(receiver, stream_name, attr_name: nil, position: nil)
|
38
|
+
attr_name ||= :iterator
|
39
|
+
instance = build(stream_name, position: position)
|
40
|
+
receiver.public_send "#{attr_name}=", instance
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def next
|
45
|
+
logger.trace { "Getting next event data (Batch Length: #{(batch &.length).inspect}, Batch Index: #{batch_index})" }
|
46
|
+
|
47
|
+
resupply if batch_depleted?
|
48
|
+
|
49
|
+
message_data = batch[batch_index]
|
50
|
+
|
51
|
+
logger.debug(tags: [:data, :message_data]) { "Next event data: #{message_data.pretty_inspect}" }
|
52
|
+
logger.debug { "Done getting next event data (Batch Length: #{(batch &.length).inspect}, Batch Index: #{batch_index})" }
|
53
|
+
|
54
|
+
advance_batch_index
|
55
|
+
|
56
|
+
message_data
|
57
|
+
end
|
58
|
+
|
59
|
+
def advance_batch_index
|
60
|
+
logger.trace { "Advancing batch index (Batch Index: #{batch_index})" }
|
61
|
+
self.batch_index += 1
|
62
|
+
logger.debug { "Advanced batch index (Batch Index: #{batch_index})" }
|
63
|
+
end
|
64
|
+
|
65
|
+
def batch_depleted?
|
66
|
+
if batch.nil?
|
67
|
+
logger.debug { "Batch is depleted (Batch is nil)" }
|
68
|
+
return true
|
69
|
+
end
|
70
|
+
|
71
|
+
if batch.empty?
|
72
|
+
logger.debug { "Batch is depleted (Batch is empty)" }
|
73
|
+
return true
|
74
|
+
end
|
75
|
+
|
76
|
+
if batch_index == batch.length
|
77
|
+
logger.debug { "Batch is depleted (Batch Index: #{batch_index}, Batch Length: #{batch.length})" }
|
78
|
+
return true
|
79
|
+
end
|
80
|
+
|
81
|
+
false
|
82
|
+
end
|
83
|
+
|
84
|
+
def resupply
|
85
|
+
logger.trace { "Resupplying batch (Current Batch Length: #{(batch &.length).inspect})" }
|
86
|
+
|
87
|
+
batch = get_batch
|
88
|
+
reset(batch)
|
89
|
+
|
90
|
+
logger.debug { "Batch resupplied (Next Batch Length: #{(batch &.length).inspect})" }
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_batch
|
94
|
+
position = next_batch_starting_position
|
95
|
+
|
96
|
+
logger.trace "Getting batch (Position: #{position.inspect})"
|
97
|
+
|
98
|
+
batch = []
|
99
|
+
if position.nil? || position >= 0
|
100
|
+
batch = get.(stream_name, position: position)
|
101
|
+
end
|
102
|
+
|
103
|
+
logger.debug { "Finished getting batch (Count: #{batch.length}, Position: #{position.inspect})" }
|
104
|
+
|
105
|
+
batch
|
106
|
+
end
|
107
|
+
|
108
|
+
def next_batch_starting_position
|
109
|
+
if batch.nil?
|
110
|
+
logger.debug { "Batch is nil (Next batch starting position: #{starting_position.inspect})" }
|
111
|
+
return starting_position
|
112
|
+
end
|
113
|
+
|
114
|
+
previous_position = last_position
|
115
|
+
next_position = previous_position + 1
|
116
|
+
logger.debug { "End of batch (Next starting position: #{next_position}, Previous Position: #{previous_position})" }
|
117
|
+
|
118
|
+
next_position
|
119
|
+
end
|
120
|
+
|
121
|
+
def reset(batch)
|
122
|
+
logger.trace { "Resetting batch" }
|
123
|
+
|
124
|
+
self.batch = batch
|
125
|
+
self.batch_index = 0
|
126
|
+
|
127
|
+
logger.debug(tags: [:data, :batch]) { "Batch set to: \n#{batch.pretty_inspect}" }
|
128
|
+
logger.debug(tags: [:data, :batch]) { "Batch position set to: #{batch_index.inspect}" }
|
129
|
+
logger.debug { "Done resetting batch" }
|
130
|
+
end
|
131
|
+
|
132
|
+
class Substitute
|
133
|
+
include Read::Iterator
|
134
|
+
|
135
|
+
initializer :stream_name
|
136
|
+
|
137
|
+
def self.build()
|
138
|
+
new('some_stream_name')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module StreamName
|
3
|
+
def self.stream_name(category_name, id=nil, type: nil, types: nil)
|
4
|
+
types = Array(types)
|
5
|
+
types.unshift(type) unless type.nil?
|
6
|
+
|
7
|
+
type_list = nil
|
8
|
+
type_list = types.join('+') unless types.empty?
|
9
|
+
|
10
|
+
stream_name = category_name
|
11
|
+
stream_name = "#{stream_name}:#{type_list}" unless type_list.nil?
|
12
|
+
stream_name = "#{stream_name}-#{id}" unless id.nil?
|
13
|
+
|
14
|
+
stream_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.get_id(stream_name)
|
18
|
+
id = stream_name.partition('-').last
|
19
|
+
id.empty? ? nil : id
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.get_category(stream_name)
|
23
|
+
stream_name.split('-').first
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.category?(stream_name)
|
27
|
+
!stream_name.include?('-')
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.get_type_list(stream_name)
|
31
|
+
type = stream_name.split(':').last.split('-').first
|
32
|
+
|
33
|
+
return nil if stream_name.start_with?(type)
|
34
|
+
|
35
|
+
type
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.get_types(stream_name)
|
39
|
+
type_list = get_type_list(stream_name)
|
40
|
+
|
41
|
+
return [] if type_list.nil?
|
42
|
+
|
43
|
+
type_list.split('+')
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.get_entity_name(stream_name)
|
47
|
+
get_category(stream_name).split(':').first
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module MessageStore
|
2
|
+
module Write
|
3
|
+
def self.included(cls)
|
4
|
+
cls.class_exec do
|
5
|
+
include Log::Dependency
|
6
|
+
|
7
|
+
cls.extend Build
|
8
|
+
cls.extend Call
|
9
|
+
cls.extend Configure
|
10
|
+
|
11
|
+
dependency :identifier, Identifier::UUID::Random
|
12
|
+
|
13
|
+
abstract :configure
|
14
|
+
abstract :write
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module Build
|
19
|
+
def build(session: nil)
|
20
|
+
instance = new
|
21
|
+
Identifier::UUID::Random.configure(instance)
|
22
|
+
instance.configure(session: session)
|
23
|
+
instance
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Configure
|
28
|
+
def configure(receiver, session: nil, attr_name: nil)
|
29
|
+
attr_name ||= :write
|
30
|
+
instance = build(session: session)
|
31
|
+
receiver.public_send "#{attr_name}=", instance
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module Call
|
36
|
+
def call(message_data, stream_name, expected_version: nil, session: nil)
|
37
|
+
instance = build(session: session)
|
38
|
+
instance.(message_data, stream_name, expected_version: expected_version)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def call(message_data, stream_name, expected_version: nil)
|
43
|
+
logger.trace(tag: :write) { "Writing event data (Stream Name: #{stream_name}, Expected Version: #{expected_version.inspect})" }
|
44
|
+
logger.trace(tags: [:data, :message_data, :write]) { message_data.pretty_inspect }
|
45
|
+
|
46
|
+
batch = Array(message_data)
|
47
|
+
|
48
|
+
set_ids(batch)
|
49
|
+
|
50
|
+
position = write(batch, stream_name, expected_version: expected_version)
|
51
|
+
|
52
|
+
logger.info(tag: :write) { "Wrote event data (Stream Name: #{stream_name}, Expected Version: #{expected_version.inspect})" }
|
53
|
+
logger.info(tags: [:data, :message_data, :write]) { message_data.pretty_inspect }
|
54
|
+
|
55
|
+
position
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_ids(batch)
|
59
|
+
batch.each do |message_data|
|
60
|
+
if message_data.id.nil?
|
61
|
+
message_data.id = identifier.get
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
metadata
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: evt-message_store
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- The Eventide Project
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-05-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: evt-casing
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: evt-schema
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: evt-initializer
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: evt-identifier-uuid
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: evt-transform
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: evt-virtual
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: evt-async_invocation
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: test_bench
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: " "
|
126
|
+
email: opensource@eventide-project.org
|
127
|
+
executables: []
|
128
|
+
extensions: []
|
129
|
+
extra_rdoc_files: []
|
130
|
+
files:
|
131
|
+
- lib/message_store.rb
|
132
|
+
- lib/message_store/controls.rb
|
133
|
+
- lib/message_store/controls/category.rb
|
134
|
+
- lib/message_store/controls/get.rb
|
135
|
+
- lib/message_store/controls/id.rb
|
136
|
+
- lib/message_store/controls/iterator.rb
|
137
|
+
- lib/message_store/controls/message_data.rb
|
138
|
+
- lib/message_store/controls/message_data/hash.rb
|
139
|
+
- lib/message_store/controls/message_data/metadata.rb
|
140
|
+
- lib/message_store/controls/message_data/read.rb
|
141
|
+
- lib/message_store/controls/message_data/write.rb
|
142
|
+
- lib/message_store/controls/random_value.rb
|
143
|
+
- lib/message_store/controls/read.rb
|
144
|
+
- lib/message_store/controls/stream_name.rb
|
145
|
+
- lib/message_store/controls/time.rb
|
146
|
+
- lib/message_store/controls/write.rb
|
147
|
+
- lib/message_store/expected_version.rb
|
148
|
+
- lib/message_store/get.rb
|
149
|
+
- lib/message_store/log.rb
|
150
|
+
- lib/message_store/message_data.rb
|
151
|
+
- lib/message_store/message_data/hash.rb
|
152
|
+
- lib/message_store/message_data/read.rb
|
153
|
+
- lib/message_store/message_data/write.rb
|
154
|
+
- lib/message_store/no_stream.rb
|
155
|
+
- lib/message_store/read.rb
|
156
|
+
- lib/message_store/read/iterator.rb
|
157
|
+
- lib/message_store/stream_name.rb
|
158
|
+
- lib/message_store/write.rb
|
159
|
+
homepage: https://github.com/eventide-project/message-store
|
160
|
+
licenses:
|
161
|
+
- MIT
|
162
|
+
metadata: {}
|
163
|
+
post_install_message:
|
164
|
+
rdoc_options: []
|
165
|
+
require_paths:
|
166
|
+
- lib
|
167
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - ">="
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: 2.4.0
|
172
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
requirements: []
|
178
|
+
rubyforge_project:
|
179
|
+
rubygems_version: 2.6.11
|
180
|
+
signing_key:
|
181
|
+
specification_version: 4
|
182
|
+
summary: Common primitives for platform-specific message store implementations
|
183
|
+
test_files: []
|