deimos-ruby 2.1.6 → 2.1.7
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/CHANGELOG.md +4 -0
- data/docs/CONFIGURATION.md +10 -10
- data/lib/deimos/active_record_consume/batch_record_list.rb +3 -0
- data/lib/deimos/version.rb +1 -1
- data/spec/active_record_consume/mass_updater_spec.rb +187 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3890d253c7d9b137c55d02e1968697b9a2921a8cd57dec3be49b6eb3ea50d670
|
4
|
+
data.tar.gz: 4538ffbef398ea60d5fe1f3cd20e30a1fe4e45c00e2369717ea160491554d687
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 221bf0e05c603dda8f6451d4205ed4ea86f209fe8bdc4d6c43c5ad1a19aff57c9df80f9a82a3c134a31e78b6072eab076d6f3e8594fb8a01f4892857068f9aa0
|
7
|
+
data.tar.gz: 41cec49b3a6913617398bf194fd1d8fb65304231b34aca051fad5c37307b2e617b571c220ff95aefec57b2200564a9827bddd37ae80553a8091d784561f0c6d5
|
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.7 - 2025-07-23
|
11
|
+
|
12
|
+
- Feature: Skip batch_record_list fill_primary_keys! if the primary key has already been filled during consumption
|
13
|
+
|
10
14
|
# 2.1.6 - 2025-07-23
|
11
15
|
|
12
16
|
- Fix: Allows rails to handle querying bulk_import_id when replacing associations for non-string bulk_import_ids
|
data/docs/CONFIGURATION.md
CHANGED
@@ -120,16 +120,16 @@ The following are additional settings that can be added to the `topic` block in
|
|
120
120
|
|
121
121
|
### Consumer Settings
|
122
122
|
|
123
|
-
| Config name | Default | Description
|
124
|
-
|
125
|
-
| each_message | false | If true, use `consume_message` for each message rather than `consume_batch` for the full batch.
|
126
|
-
| reraise_errors | false | Default behavior is to swallow uncaught exceptions and log to the metrics provider. Set this to true to instead raise all errors. Note that raising an error will ensure that the message cannot be processed - if there is a bad message which will always raise that error, your consumer will not be able to proceed past it and will be stuck forever until you fix your code. See also the fatal_error configuration.
|
127
|
-
| fatal_error | `proc { false }` | Block taking an exception, payload and metadata and returning true if this should be considered a fatal error and false otherwise. E.g. you can use this to always fail if the database is available. Not needed if reraise_errors is set to true.
|
128
|
-
| max_db_batch_size | nil | Maximum limit for batching database calls to reduce the load on the db.
|
129
|
-
| bulk_import_id_column | `:bulk_import_id` | Name of the column to use for multi-table imports.
|
130
|
-
| replace_associations | true | If false, append to associations in multi-table imports rather than replacing them.
|
131
|
-
| bulk_import_id_generator | nil | Block to determine the bulk_import_id generated during bulk consumption. If no block is specified the provided/default block from the consumers configuration will be used.
|
132
|
-
| save_associations_first |false|Whether to save associated records of primary class prior to upserting primary records. Foreign key of associated records are assigned to the record class prior to saving the record class
|
123
|
+
| Config name | Default | Description |
|
124
|
+
|--------------------------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
125
|
+
| each_message | false | If true, use `consume_message` for each message rather than `consume_batch` for the full batch. |
|
126
|
+
| reraise_errors | false | Default behavior is to swallow uncaught exceptions and log to the metrics provider. Set this to true to instead raise all errors. Note that raising an error will ensure that the message cannot be processed - if there is a bad message which will always raise that error, your consumer will not be able to proceed past it and will be stuck forever until you fix your code. See also the fatal_error configuration. |
|
127
|
+
| fatal_error | `proc { false }` | Block taking an exception, payload and metadata and returning true if this should be considered a fatal error and false otherwise. E.g. you can use this to always fail if the database is available. Not needed if reraise_errors is set to true. |
|
128
|
+
| max_db_batch_size | nil | Maximum limit for batching database calls to reduce the load on the db. |
|
129
|
+
| bulk_import_id_column | `:bulk_import_id` | Name of the column to use for multi-table imports. |
|
130
|
+
| replace_associations | true | If false, append to associations in multi-table imports rather than replacing them. |
|
131
|
+
| bulk_import_id_generator | nil | Block to determine the bulk_import_id generated during bulk consumption. If no block is specified the provided/default block from the consumers configuration will be used. |
|
132
|
+
| save_associations_first | false | Whether to save associated records of primary class prior to upserting primary records. Foreign key of associated records are assigned to the record class prior to saving the record class |
|
133
133
|
|
134
134
|
### Defining Consumers
|
135
135
|
|
@@ -52,6 +52,9 @@ module Deimos
|
|
52
52
|
# records.
|
53
53
|
def fill_primary_keys!
|
54
54
|
primary_col = self.klass.primary_key
|
55
|
+
|
56
|
+
return if self.batch_records.empty? || self.batch_records.first.send(primary_col).present?
|
57
|
+
|
55
58
|
bulk_import_map = self.klass.
|
56
59
|
where(self.bulk_import_column => self.batch_records.map(&:bulk_import_id)).
|
57
60
|
select(primary_col, self.bulk_import_column).
|
data/lib/deimos/version.rb
CHANGED
@@ -251,5 +251,192 @@ RSpec.describe Deimos::ActiveRecordConsume::MassUpdater do
|
|
251
251
|
|
252
252
|
end
|
253
253
|
|
254
|
+
context 'with recorded primary_keys' do
|
255
|
+
before(:all) do
|
256
|
+
ActiveRecord::Base.connection.create_table(:fidgets, force: true, id: false) do |t|
|
257
|
+
t.string :test_id, primary_key: true
|
258
|
+
t.integer(:some_int)
|
259
|
+
t.string(:bulk_import_id)
|
260
|
+
t.timestamps
|
261
|
+
end
|
262
|
+
|
263
|
+
ActiveRecord::Base.connection.create_table(:fidget_details, force: true) do |t|
|
264
|
+
t.string(:title)
|
265
|
+
t.string(:bulk_import_id)
|
266
|
+
t.belongs_to(:fidget)
|
267
|
+
|
268
|
+
t.index(%i(title), unique: true)
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
|
273
|
+
after(:all) do
|
274
|
+
ActiveRecord::Base.connection.drop_table(:fidgets)
|
275
|
+
ActiveRecord::Base.connection.drop_table(:fidget_details)
|
276
|
+
end
|
277
|
+
|
278
|
+
let(:fidget_detail_class) do
|
279
|
+
Class.new(ActiveRecord::Base) do
|
280
|
+
self.table_name = 'fidget_details'
|
281
|
+
belongs_to :fidget
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
let(:fidget_class) do
|
286
|
+
Class.new(ActiveRecord::Base) do
|
287
|
+
self.table_name = 'fidgets'
|
288
|
+
has_one :fidget_detail
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
let(:bulk_id_generator) { proc { SecureRandom.uuid } }
|
293
|
+
|
294
|
+
let(:key_proc) do
|
295
|
+
lambda do |klass|
|
296
|
+
case klass.to_s
|
297
|
+
when 'Fidget'
|
298
|
+
%w(test_id)
|
299
|
+
when 'FidgetDetail'
|
300
|
+
%w(title)
|
301
|
+
else
|
302
|
+
raise "Key Columns for #{klass} not defined"
|
303
|
+
end
|
304
|
+
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
before(:each) do
|
309
|
+
stub_const('Fidget', fidget_class)
|
310
|
+
stub_const('FidgetDetail', fidget_detail_class)
|
311
|
+
Fidget.reset_column_information
|
312
|
+
end
|
313
|
+
|
314
|
+
|
315
|
+
let(:batch) do
|
316
|
+
Deimos::ActiveRecordConsume::BatchRecordList.new(
|
317
|
+
[
|
318
|
+
Deimos::ActiveRecordConsume::BatchRecord.new(
|
319
|
+
klass: Fidget,
|
320
|
+
attributes: { test_id: 'id1', some_int: 5, fidget_detail: { title: 'Title 1' } },
|
321
|
+
bulk_import_column: 'bulk_import_id',
|
322
|
+
bulk_import_id_generator: bulk_id_generator
|
323
|
+
),
|
324
|
+
Deimos::ActiveRecordConsume::BatchRecord.new(
|
325
|
+
klass: Fidget,
|
326
|
+
attributes: { test_id: 'id2', some_int: 10, fidget_detail: { title: 'Title 2' } },
|
327
|
+
bulk_import_column: 'bulk_import_id',
|
328
|
+
bulk_import_id_generator: bulk_id_generator
|
329
|
+
)
|
330
|
+
]
|
331
|
+
)
|
332
|
+
end
|
333
|
+
|
334
|
+
it 'should not backfill the primary key when the primary_key exists' do
|
335
|
+
allow(Fidget).to receive(:where).and_call_original
|
336
|
+
results = described_class.new(Widget,
|
337
|
+
bulk_import_id_generator: bulk_id_generator,
|
338
|
+
bulk_import_id_column: 'bulk_import_id',
|
339
|
+
key_col_proc: key_proc).mass_update(batch)
|
340
|
+
expect(results.count).to eq(2)
|
341
|
+
expect(Fidget.count).to eq(2)
|
342
|
+
expect(Fidget).not_to have_received(:where).with(:bulk_import_id => [instance_of(String), instance_of(String)])
|
343
|
+
end
|
344
|
+
|
345
|
+
end
|
346
|
+
|
347
|
+
context 'without recorded primary_keys' do
|
348
|
+
before(:all) do
|
349
|
+
ActiveRecord::Base.connection.create_table(:fidgets, force: true) do |t|
|
350
|
+
t.string(:test_id)
|
351
|
+
t.integer(:some_int)
|
352
|
+
t.string(:bulk_import_id)
|
353
|
+
t.timestamps
|
354
|
+
end
|
355
|
+
|
356
|
+
ActiveRecord::Base.connection.create_table(:fidget_details, force: true) do |t|
|
357
|
+
t.string(:title)
|
358
|
+
t.string(:bulk_import_id)
|
359
|
+
t.belongs_to(:fidget)
|
360
|
+
|
361
|
+
t.index(%i(title), unique: true)
|
362
|
+
end
|
363
|
+
|
364
|
+
end
|
365
|
+
|
366
|
+
after(:all) do
|
367
|
+
ActiveRecord::Base.connection.drop_table(:fidgets)
|
368
|
+
ActiveRecord::Base.connection.drop_table(:fidget_details)
|
369
|
+
end
|
370
|
+
|
371
|
+
let(:fidget_detail_class) do
|
372
|
+
Class.new(ActiveRecord::Base) do
|
373
|
+
self.table_name = 'fidget_details'
|
374
|
+
belongs_to :fidget
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
let(:fidget_class) do
|
379
|
+
Class.new(ActiveRecord::Base) do
|
380
|
+
self.table_name = 'fidgets'
|
381
|
+
has_one :fidget_detail
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
let(:bulk_id_generator) { proc { SecureRandom.uuid } }
|
386
|
+
|
387
|
+
let(:key_proc) do
|
388
|
+
lambda do |klass|
|
389
|
+
case klass.to_s
|
390
|
+
when 'Fidget'
|
391
|
+
%w(id)
|
392
|
+
when 'FidgetDetail'
|
393
|
+
%w(title)
|
394
|
+
else
|
395
|
+
raise "Key Columns for #{klass} not defined"
|
396
|
+
end
|
397
|
+
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
before(:each) do
|
402
|
+
stub_const('Fidget', fidget_class)
|
403
|
+
stub_const('FidgetDetail', fidget_detail_class)
|
404
|
+
Fidget.reset_column_information
|
405
|
+
end
|
406
|
+
|
407
|
+
|
408
|
+
let(:batch) do
|
409
|
+
Deimos::ActiveRecordConsume::BatchRecordList.new(
|
410
|
+
[
|
411
|
+
Deimos::ActiveRecordConsume::BatchRecord.new(
|
412
|
+
klass: Fidget,
|
413
|
+
attributes: { test_id: 'id1', some_int: 5, fidget_detail: { title: 'Title 1' } },
|
414
|
+
bulk_import_column: 'bulk_import_id',
|
415
|
+
bulk_import_id_generator: bulk_id_generator
|
416
|
+
),
|
417
|
+
Deimos::ActiveRecordConsume::BatchRecord.new(
|
418
|
+
klass: Fidget,
|
419
|
+
attributes: { test_id: 'id2', some_int: 10, fidget_detail: { title: 'Title 2' } },
|
420
|
+
bulk_import_column: 'bulk_import_id',
|
421
|
+
bulk_import_id_generator: bulk_id_generator
|
422
|
+
)
|
423
|
+
]
|
424
|
+
)
|
425
|
+
end
|
426
|
+
|
427
|
+
it 'should not backfill the primary key when the primary_key exists' do
|
428
|
+
allow(Fidget).to receive(:where).and_call_original
|
429
|
+
results = described_class.new(Widget,
|
430
|
+
bulk_import_id_generator: bulk_id_generator,
|
431
|
+
bulk_import_id_column: 'bulk_import_id',
|
432
|
+
key_col_proc: key_proc).mass_update(batch)
|
433
|
+
expect(results.count).to eq(2)
|
434
|
+
expect(Fidget.count).to eq(2)
|
435
|
+
expect(Fidget).to have_received(:where).with(:bulk_import_id => [instance_of(String), instance_of(String)])
|
436
|
+
expect(batch.records.map(&:id)).to eq([1,2])
|
437
|
+
end
|
438
|
+
|
439
|
+
end
|
440
|
+
|
254
441
|
end
|
255
442
|
end
|