emque-producing 0.0.2 → 0.0.3

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
  SHA1:
3
- metadata.gz: cc3013b37568f755a5f258d0c18b3a8e346ac219
4
- data.tar.gz: 28aad21a17a39be148e7d22611df8b4d992c85f6
3
+ metadata.gz: f07f1bcc511fa4aa8ccbe5a9c5342ff719541944
4
+ data.tar.gz: d7b89c744df15c439701549c1f756f35dd34c748
5
5
  SHA512:
6
- metadata.gz: 997635efddaa40fe279c246a3862917666b4c4d154b6809c9c69e7fe6e3a4281ffac27e8a1638c8556467f764be2cdb62a9b8d67edaf90331541e2d581b733da
7
- data.tar.gz: 5cebfd302c30b90c1863555cd5b7fce581d67d1278310a05d6ad13f4bf71e573bf9a50311204da6a74e7108de3d7f735654db85905639bf621b14f982e68dfda
6
+ metadata.gz: 06e9e100d3f6fa96200995b7f1affdf6ba6fcd843e69ea2b0cb83c4245fc8fc9fd6a97f252fabeea5cd79a2014a5b65aaa66b39c940d9b97e5d41d3c2bb02a61
7
+ data.tar.gz: 51c17c859632f0222c0ba16804e091b4e4664357e6b844bf37947eab6b56a7b20507cd1d753da94307f5441cb9558ecf72e75be2a6155bd2e1de4624b4f48645
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- emque-producing (0.0.2)
4
+ emque-producing (0.0.3)
5
5
  oj (~> 2.10.2)
6
6
  virtus (~> 1.0.3)
7
7
 
@@ -6,3 +6,4 @@ require "emque/producing/configuration"
6
6
  require "emque/producing/logging"
7
7
  require "emque/producing/publisher/base"
8
8
  require "emque/producing/message/message"
9
+ require "emque/producing/message/message_with_changeset"
@@ -1,4 +1,5 @@
1
- require 'securerandom'
1
+ require "securerandom"
2
+ require "socket"
2
3
 
3
4
  module Emque
4
5
  module Producing
@@ -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
@@ -1,5 +1,5 @@
1
1
  module Emque
2
2
  module Producing
3
- VERSION = "0.0.2"
3
+ VERSION = "0.0.3"
4
4
  end
5
5
  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::Message
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::Message
47
+ include Emque::Producing.message
17
48
  message_type "testing"
18
49
  end
19
50
 
20
51
  class MessageNoType
21
- include Emque::Producing::Message
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 = "apiv3"
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("apiv3")
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("apiv3")
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.2
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-06 00:00:00.000000000 Z
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