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 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