deimos-ruby 2.1.8 → 2.1.9

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
  SHA256:
3
- metadata.gz: db2890edc1a3d0148f1d2d17d488956140403691807b782b14fb59ab85e5eb70
4
- data.tar.gz: 559be5246d5793112335575066f02ec07ed4310baf86bdb630a076d448770714
3
+ metadata.gz: 52b13a01b0356e08ceb56ae75eb55f39d6578070085184521e063d7fb3714f1f
4
+ data.tar.gz: 36f972a37d52c3c8fb3ea5e53c21c1f39caad58fa8411f0dc380b5a8b7f1ed9e
5
5
  SHA512:
6
- metadata.gz: 75f32bba6112ba1cabb233c9333bb0f6e56029d30a85d24ccca5057302f103b76482e364fb183f3f8fa545f3dbb75f4f03404f4b12392ec4e8c4bea199a8ccf7
7
- data.tar.gz: a8a745e864fd29d442fd4a4f474f58428f3ffe7fee1ea41e50ebebff8121da0aba8c91c5605ac6c991b91fe7ccb6ff03fbabf203dc296beb43e60e13f3b9c991
6
+ metadata.gz: e5d2c15d11756bc133f1ea57e9c112023c557aa6200a4ac7469f9b07f23835d16593ae6ef9d4e20c76dcb4a6acff9d4723355e14ec6e28d1887e09958a6f3283
7
+ data.tar.gz: d9f1e82068b7f5c7424590fda13a4d59fa9345dc3841c9b1f8413248f031548b276fa5660d39c9fe4f5621bc47089049f70af97d207e3f02af5122d3971c10a9
data/CHANGELOG.md CHANGED
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## UNRELEASED
9
9
 
10
+ # 2.1.9 - 2025-08-13
11
+
12
+ - Fix: When a model uses multiple producers, `send_kafka_event_on_update` no longer aggregates `watched_attributes` across all producers and publishes to all of them if any field changed. It now evaluates each producer’s `watched_attributes` independently and publishes only to the producers whose fields changed (per‑producer isolation).
13
+
10
14
  # 2.1.8 - 2025-08-11
11
15
 
12
16
  - Feature: Producers can now customize the deletion payload, so different producers using the same model can send different delete messages.
@@ -27,18 +27,21 @@ module Deimos
27
27
  def send_kafka_event_on_update
28
28
  return unless self.class.kafka_config[:update]
29
29
 
30
- producers = self.class.kafka_producers
31
- fields = producers.flat_map { |p| p.watched_attributes(self) }.uniq
32
- fields -= ['updated_at']
33
- # Only send an event if a field we care about was changed.
34
- any_changes = fields.any? do |field|
35
- field_change = self.previous_changes[field]
36
- field_change.present? && field_change[0] != field_change[1]
37
- end
38
- return unless any_changes
39
30
  self.truncate_columns if Deimos.config.producers.truncate_columns
40
31
 
41
- producers.each { |p| p.send_event(self) }
32
+ producers = self.class.kafka_producers
33
+ producers.each do |producer|
34
+ fields = producer.watched_attributes(self)
35
+ fields -= ['updated_at']
36
+ # Only send an event if a field we care about was changed.
37
+ any_changes = fields.any? do |field|
38
+ field_change = self.previous_changes[field]
39
+ field_change.present? && field_change[0] != field_change[1]
40
+ end
41
+ next unless any_changes
42
+
43
+ producer.send_event(self)
44
+ end
42
45
  end
43
46
 
44
47
  # Send a deletion (null payload) event to Kafka.
@@ -82,7 +85,7 @@ module Deimos
82
85
  # @!visibility private
83
86
  def import_without_validations_or_callbacks(column_names,
84
87
  array_of_attributes,
85
- options={})
88
+ options = {})
86
89
  results = super
87
90
  if !self.kafka_config[:import] || array_of_attributes.empty?
88
91
  return results
@@ -112,7 +115,8 @@ module Deimos
112
115
  last_id = if self.connection.adapter_name.downcase =~ /sqlite/
113
116
  self.connection.select_value('select last_insert_rowid()') -
114
117
  hashes_without_id.size + 1
115
- else # mysql
118
+ else
119
+ # mysql
116
120
  self.connection.select_value('select LAST_INSERT_ID()')
117
121
  end
118
122
  hashes_without_id.each_with_index do |attrs, i|
@@ -130,6 +134,7 @@ module Deimos
130
134
  self.class.columns.each do |col|
131
135
  next unless col.type == :string
132
136
  next if self[col.name].blank?
137
+
133
138
  if self[col.name].to_s.length > col.limit
134
139
  self[col.name] = self[col.name][0..col.limit - 1]
135
140
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Deimos
4
- VERSION = '2.1.8'
4
+ VERSION = '2.1.9'
5
5
  end
@@ -17,10 +17,16 @@ module KafkaSourceSpec
17
17
 
18
18
  # Dummy producer which mimicks the behavior of a real producer
19
19
  class WidgetProducer < Deimos::ActiveRecordProducer
20
+ def self.watched_attributes(_record)
21
+ %w(name widget_id)
22
+ end
20
23
  end
21
24
 
22
25
  # Dummy producer which mimicks the behavior of a real producer
23
26
  class WidgetProducerTheSecond < Deimos::ActiveRecordProducer
27
+ def self.watched_attributes(_record)
28
+ %w(description widget_id)
29
+ end
24
30
  end
25
31
 
26
32
  # Dummy class we can include the mixin in. Has a backing table created
@@ -122,7 +128,6 @@ module KafkaSourceSpec
122
128
  def generate_payload(attributes, record)
123
129
  payload = super(attributes, record)
124
130
  payload.merge('id' => record.model_id)
125
-
126
131
  end
127
132
 
128
133
  def generate_deletion_payload(record)
@@ -182,6 +187,7 @@ module KafkaSourceSpec
182
187
  before(:each) do
183
188
  Deimos.config.producers.truncate_columns = false
184
189
  end
190
+
185
191
  it 'should not truncate values' do
186
192
  widget = Widget.create!(widget_id: 1, name: 'a' * 500)
187
193
  expect('my-topic').to have_sent({
@@ -206,6 +212,7 @@ module KafkaSourceSpec
206
212
  before(:each) do
207
213
  Deimos.config.producers.truncate_columns = true
208
214
  end
215
+
209
216
  it 'should truncate values' do
210
217
  widget = Widget.create!(widget_id: 1, name: 'a' * 500)
211
218
  expect('my-topic').to have_sent({
@@ -466,5 +473,41 @@ module KafkaSourceSpec
466
473
  }.to raise_error(Deimos::MissingImplementationError)
467
474
  end
468
475
  end
476
+
477
+ describe 'Isolated watched‑attribute per producer when send_kafka_event_on_update' do
478
+ it 'should only send events to producers that watch the name field' do
479
+ widget = Widget.create!(widget_id: 1, name: 'initial', description: 'initial desc')
480
+ clear_kafka_messages!
481
+
482
+ widget.update_attribute(:name, 'updated name')
483
+
484
+ expect('my-topic').to have_sent(hash_including(name: 'updated name'))
485
+ expect('my-topic-the-second').not_to have_sent(anything)
486
+ end
487
+
488
+ it 'should only send events to producers that watch the description field' do
489
+ widget = Widget.create!(widget_id: 1, name: 'test', description: 'initial desc')
490
+ clear_kafka_messages!
491
+
492
+ widget.update_attribute(:description, 'updated description')
493
+
494
+ expect('my-topic-the-second').to have_sent(anything)
495
+ expect('my-topic').not_to have_sent(anything)
496
+ end
497
+
498
+ it 'should send events to all producers when a commonly watched field changes' do
499
+ allow(WidgetProducer).to receive(:watched_attributes).and_return(%w(name widget_id))
500
+ allow(WidgetProducerTheSecond).to receive(:watched_attributes).and_return(%w(description widget_id))
501
+
502
+ widget = Widget.create!(widget_id: 1, name: 'test', description: 'test desc')
503
+ clear_kafka_messages!
504
+
505
+ widget.update_attribute(:widget_id, 999)
506
+
507
+ expect('my-topic').to have_sent(hash_including(widget_id: 999))
508
+ expect('my-topic-the-second').to have_sent(hash_including(widget_id: 999))
509
+ end
510
+ end
511
+
469
512
  end
470
513
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deimos-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.8
4
+ version: 2.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Orner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-08-11 00:00:00.000000000 Z
11
+ date: 2025-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: avro_turf