emque-producing 0.0.2 → 0.0.3
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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/emque/producing.rb +1 -0
- data/lib/emque/producing/message/message.rb +2 -1
- data/lib/emque/producing/message/message_with_changeset.rb +59 -0
- data/lib/emque/producing/producing.rb +14 -0
- data/lib/emque/producing/version.rb +1 -1
- data/spec/producing/message/changes_payload_generator_spec.rb +65 -0
- data/spec/producing/message/message_spec.rb +135 -6
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f07f1bcc511fa4aa8ccbe5a9c5342ff719541944
|
4
|
+
data.tar.gz: d7b89c744df15c439701549c1f756f35dd34c748
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06e9e100d3f6fa96200995b7f1affdf6ba6fcd843e69ea2b0cb83c4245fc8fc9fd6a97f252fabeea5cd79a2014a5b65aaa66b39c940d9b97e5d41d3c2bb02a61
|
7
|
+
data.tar.gz: 51c17c859632f0222c0ba16804e091b4e4664357e6b844bf37947eab6b56a7b20507cd1d753da94307f5441cb9558ecf72e75be2a6155bd2e1de4624b4f48645
|
data/Gemfile.lock
CHANGED
data/lib/emque/producing.rb
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
module Emque
|
2
|
+
module Producing
|
3
|
+
module MessageWithChangeset
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:include, Emque::Producing::Message)
|
6
|
+
base.send(:attribute, :partition_key, String, :default => nil, :required => false)
|
7
|
+
base.send(:attribute, :change_set, Hash, :default => :build_change_set, :required => true)
|
8
|
+
base.send(:private_attribute, :updated)
|
9
|
+
base.send(:private_attribute, :original)
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_change_set
|
13
|
+
ChangesPayloadGenerator
|
14
|
+
.new({:original => original, :updated => updated})
|
15
|
+
.execute
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_id
|
19
|
+
if updated
|
20
|
+
updated.fetch("id") { updated[:id] }
|
21
|
+
elsif original
|
22
|
+
original.fetch("id") { original[:id] }
|
23
|
+
else
|
24
|
+
raise Emque::Producing::Message::InvalidMessageError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class ChangesPayloadGenerator
|
30
|
+
def initialize(opts = {})
|
31
|
+
@original = opts.fetch(:original, {}) || {}
|
32
|
+
@updated = opts.fetch(:updated, {}) || {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def execute
|
36
|
+
{:original => original, :updated => updated, :delta => delta}
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_reader :original, :updated
|
42
|
+
|
43
|
+
def delta
|
44
|
+
if original.empty?
|
45
|
+
:_created
|
46
|
+
elsif updated.empty?
|
47
|
+
:_deleted
|
48
|
+
else
|
49
|
+
_delta = updated
|
50
|
+
.reject { |attr, val| original[attr] == val }
|
51
|
+
.map { |attr, val|
|
52
|
+
[attr, {:original => original[attr], :updated => val}]
|
53
|
+
}
|
54
|
+
Hash[_delta]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -4,6 +4,20 @@ module Emque
|
|
4
4
|
attr_accessor :publisher
|
5
5
|
attr_writer :configuration
|
6
6
|
|
7
|
+
def message(opts = {})
|
8
|
+
with_changeset = opts.fetch(:with_changeset) { false }
|
9
|
+
|
10
|
+
Module.new do
|
11
|
+
define_singleton_method(:included) do |descendant|
|
12
|
+
if with_changeset
|
13
|
+
descendant.send(:include, ::Emque::Producing::MessageWithChangeset)
|
14
|
+
else
|
15
|
+
descendant.send(:include, ::Emque::Producing::Message)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
7
21
|
def configure
|
8
22
|
yield(configuration)
|
9
23
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "virtus"
|
3
|
+
require "emque/producing/message/message_with_changeset"
|
4
|
+
|
5
|
+
class FakeModel
|
6
|
+
include Virtus.model
|
7
|
+
|
8
|
+
attribute :foo, Integer
|
9
|
+
attribute :bar, Integer
|
10
|
+
attribute :baz, Integer
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Emque::Producing::ChangesPayloadGenerator do
|
14
|
+
context "creating object" do
|
15
|
+
it "returns a correctly formatted payload" do
|
16
|
+
object = FakeModel.new(:foo => 1, :bar => 2, :baz => 3)
|
17
|
+
generator = Emque::Producing::ChangesPayloadGenerator.new(:updated => object.attributes)
|
18
|
+
payload = generator.execute
|
19
|
+
|
20
|
+
expect(payload).to eq(
|
21
|
+
{
|
22
|
+
:original => {},
|
23
|
+
:updated => {:foo => 1, :bar => 2, :baz => 3},
|
24
|
+
:delta => :_created
|
25
|
+
}
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "updating object" do
|
31
|
+
it "returns a correctly formatted payload" do
|
32
|
+
original = FakeModel.new(:foo => 1, :bar => 2, :baz => 3)
|
33
|
+
updated = original.dup
|
34
|
+
updated.attributes = {:foo => 4}
|
35
|
+
generator = Emque::Producing::ChangesPayloadGenerator.new(
|
36
|
+
:original => original.attributes, :updated => updated.attributes
|
37
|
+
)
|
38
|
+
payload = generator.execute
|
39
|
+
|
40
|
+
expect(payload).to eq(
|
41
|
+
{
|
42
|
+
:original => {:foo => 1, :bar => 2, :baz => 3},
|
43
|
+
:updated => {:foo => 4, :bar => 2, :baz => 3},
|
44
|
+
:delta => {:foo => {:original => 1, :updated => 4}}
|
45
|
+
}
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "deleting object" do
|
51
|
+
it "returns a correctly formatted payload" do
|
52
|
+
object = FakeModel.new(:foo => 1, :bar => 2, :baz => 3)
|
53
|
+
generator = Emque::Producing::ChangesPayloadGenerator.new(:original => object.attributes)
|
54
|
+
payload = generator.execute
|
55
|
+
|
56
|
+
expect(payload).to eq(
|
57
|
+
{
|
58
|
+
:original => {:foo => 1, :bar => 2, :baz => 3},
|
59
|
+
:updated => {},
|
60
|
+
:delta => :_deleted
|
61
|
+
}
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -1,9 +1,40 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
require "virtus"
|
3
3
|
require "emque/producing/message/message"
|
4
|
+
require "emque/producing/message/message_with_changeset"
|
5
|
+
|
6
|
+
class TestMessageWithChangeset
|
7
|
+
include Emque::Producing.message(:with_changeset => true)
|
8
|
+
|
9
|
+
topic "queue"
|
10
|
+
message_type "queue.new"
|
11
|
+
|
12
|
+
attribute :test_id, Integer, :required => true, :default => :build_id
|
13
|
+
private_attribute :extra, String, :default => "value"
|
14
|
+
end
|
15
|
+
|
16
|
+
class TestMessageWithChangesetCustomBuildId
|
17
|
+
include Emque::Producing.message(:with_changeset => true)
|
18
|
+
|
19
|
+
topic "queue"
|
20
|
+
message_type "queue.new"
|
21
|
+
|
22
|
+
attribute :test_uuid, Integer, :required => true, :default => :build_id
|
23
|
+
private_attribute :extra, String, :default => "value"
|
24
|
+
|
25
|
+
def build_id
|
26
|
+
if updated
|
27
|
+
updated.fetch("uuid") { updated[:uuid] }
|
28
|
+
elsif original
|
29
|
+
original.fetch("uuid") { original[:uuid] }
|
30
|
+
else
|
31
|
+
raise Emque::Producing::Message::InvalidMessageError
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
4
35
|
|
5
36
|
class TestMessage
|
6
|
-
include Emque::Producing
|
37
|
+
include Emque::Producing.message
|
7
38
|
|
8
39
|
topic "queue"
|
9
40
|
message_type "queue.new"
|
@@ -13,19 +44,19 @@ class TestMessage
|
|
13
44
|
end
|
14
45
|
|
15
46
|
class MessageNoTopic
|
16
|
-
include Emque::Producing
|
47
|
+
include Emque::Producing.message
|
17
48
|
message_type "testing"
|
18
49
|
end
|
19
50
|
|
20
51
|
class MessageNoType
|
21
|
-
include Emque::Producing
|
52
|
+
include Emque::Producing.message
|
22
53
|
topic "testing"
|
23
54
|
end
|
24
55
|
|
25
56
|
describe Emque::Producing::Message do
|
26
57
|
before do
|
27
58
|
Emque::Producing.configure do |c|
|
28
|
-
c.app_name = "
|
59
|
+
c.app_name = "my_app"
|
29
60
|
end
|
30
61
|
end
|
31
62
|
|
@@ -33,12 +64,12 @@ describe Emque::Producing::Message do
|
|
33
64
|
it "creates the metadata" do
|
34
65
|
message = TestMessage.new(:test_id => 1)
|
35
66
|
metadata = message.add_metadata[:metadata]
|
36
|
-
expect(metadata[:app]).to eql("
|
67
|
+
expect(metadata[:app]).to eql("my_app")
|
37
68
|
end
|
38
69
|
|
39
70
|
it "can be transformed to json" do
|
40
71
|
message = Oj.load(TestMessage.new().to_json)
|
41
|
-
expect(message["metadata"]["app"]).to eql("
|
72
|
+
expect(message["metadata"]["app"]).to eql("my_app")
|
42
73
|
end
|
43
74
|
|
44
75
|
it "includes valid attributes in json" do
|
@@ -85,4 +116,102 @@ describe Emque::Producing::Message do
|
|
85
116
|
message = TestMessage.new()
|
86
117
|
expect(message.add_metadata[:metadata][:type]).to eql("queue.new")
|
87
118
|
end
|
119
|
+
|
120
|
+
context "message with changeset" do
|
121
|
+
describe "custom #build_id behavior" do
|
122
|
+
it "raises an InvalidMessageError when no updated or original object is passed in" do
|
123
|
+
expect{TestMessageWithChangesetCustomBuildId.new(:not_the_id => 1)}.to raise_error(
|
124
|
+
Emque::Producing::Message::InvalidMessageError
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "defaults to the id of the original object if not passed an updated object" do
|
129
|
+
produced_message = TestMessageWithChangesetCustomBuildId.new(
|
130
|
+
:original => {:uuid => 3, :attr => "old_value"}
|
131
|
+
)
|
132
|
+
json = produced_message.to_json
|
133
|
+
consumed_message = Oj.load(json)
|
134
|
+
expect(consumed_message["test_uuid"]).to eql(3)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "defaults to the id of the updated object if passed an id" do
|
138
|
+
produced_message = TestMessageWithChangesetCustomBuildId.new(
|
139
|
+
:original => {:uuid => 1, :attr => "old_value"},
|
140
|
+
:updated => {:uuid => 2, :attr => "new_value"}
|
141
|
+
)
|
142
|
+
json = produced_message.to_json
|
143
|
+
consumed_message = Oj.load(json)
|
144
|
+
expect(consumed_message["test_uuid"]).to eql(2)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "default #build_id behavior" do
|
149
|
+
it "raises an InvalidMessageError when no updated or original object is passed in" do
|
150
|
+
expect{TestMessageWithChangeset.new(:not_the_id => 1)}.to raise_error(
|
151
|
+
Emque::Producing::Message::InvalidMessageError
|
152
|
+
)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "defaults to the id of the original object if not passed an updated object" do
|
156
|
+
produced_message = TestMessageWithChangeset.new(
|
157
|
+
:original => {:id => 3, :attr => "old_value"}
|
158
|
+
)
|
159
|
+
json = produced_message.to_json
|
160
|
+
consumed_message = Oj.load(json)
|
161
|
+
expect(consumed_message["test_id"]).to eql(3)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "defaults to the id of the updated object if passed an id" do
|
165
|
+
produced_message = TestMessageWithChangeset.new(
|
166
|
+
:original => {:id => 1, :attr => "old_value"},
|
167
|
+
:updated => {:id => 2, :attr => "new_value"}
|
168
|
+
)
|
169
|
+
json = produced_message.to_json
|
170
|
+
consumed_message = Oj.load(json)
|
171
|
+
expect(consumed_message["test_id"]).to eql(2)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it "defaults to a changeset of 'created' when no updated or original is passed in" do
|
176
|
+
produced_message = TestMessageWithChangeset.new(:test_id => 1)
|
177
|
+
json = produced_message.to_json
|
178
|
+
consumed_message = Oj.load(json)
|
179
|
+
expect(consumed_message["change_set"]).to eql(
|
180
|
+
{"original"=>{}, "updated"=>{}, "delta"=>"_created"}
|
181
|
+
)
|
182
|
+
end
|
183
|
+
|
184
|
+
it "indicates a deleted object when the update is not passed in" do
|
185
|
+
produced_message = TestMessageWithChangeset.new(
|
186
|
+
:test_id => 1,
|
187
|
+
:original => {:attr => "old_value"}
|
188
|
+
)
|
189
|
+
json = produced_message.to_json
|
190
|
+
consumed_message = Oj.load(json)
|
191
|
+
expect(consumed_message["change_set"]).to eql(
|
192
|
+
{"original"=>{"attr"=>"old_value"}, "updated"=>{}, "delta"=>"_deleted"}
|
193
|
+
)
|
194
|
+
end
|
195
|
+
|
196
|
+
it "returns a changeset when update and original values are passed in" do
|
197
|
+
produced_message = TestMessageWithChangeset.new(
|
198
|
+
:test_id => 1,
|
199
|
+
:updated => {:attr => "new_value"},
|
200
|
+
:original => {:attr => "old_value"}
|
201
|
+
)
|
202
|
+
json = produced_message.to_json
|
203
|
+
consumed_message = Oj.load(json)
|
204
|
+
expect(consumed_message["change_set"]).to eql(
|
205
|
+
{
|
206
|
+
"original"=>{"attr"=>"old_value"},
|
207
|
+
"updated"=>{"attr"=>"new_value"},
|
208
|
+
"delta"=>{
|
209
|
+
"attr"=>{
|
210
|
+
"original"=>"old_value", "updated"=>"new_value"
|
211
|
+
}
|
212
|
+
}
|
213
|
+
}
|
214
|
+
)
|
215
|
+
end
|
216
|
+
end
|
88
217
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: emque-producing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Emily Dobervich
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-02-
|
12
|
+
date: 2015-02-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: oj
|
@@ -143,6 +143,7 @@ files:
|
|
143
143
|
- lib/emque/producing/configuration.rb
|
144
144
|
- lib/emque/producing/logging.rb
|
145
145
|
- lib/emque/producing/message/message.rb
|
146
|
+
- lib/emque/producing/message/message_with_changeset.rb
|
146
147
|
- lib/emque/producing/producing.rb
|
147
148
|
- lib/emque/producing/publisher/base.rb
|
148
149
|
- lib/emque/producing/publisher/kafka.rb
|
@@ -151,6 +152,7 @@ files:
|
|
151
152
|
- spec/bin/kafka-run-class.sh
|
152
153
|
- spec/kafka_spec_helper.rb
|
153
154
|
- spec/producing/configuration_spec.rb
|
155
|
+
- spec/producing/message/changes_payload_generator_spec.rb
|
154
156
|
- spec/producing/message/message_spec.rb
|
155
157
|
- spec/producing/producing_spec.rb
|
156
158
|
- spec/producing/publisher_spec.rb
|
@@ -184,6 +186,7 @@ test_files:
|
|
184
186
|
- spec/bin/kafka-run-class.sh
|
185
187
|
- spec/kafka_spec_helper.rb
|
186
188
|
- spec/producing/configuration_spec.rb
|
189
|
+
- spec/producing/message/changes_payload_generator_spec.rb
|
187
190
|
- spec/producing/message/message_spec.rb
|
188
191
|
- spec/producing/producing_spec.rb
|
189
192
|
- spec/producing/publisher_spec.rb
|