his_emr_api_lab 2.4.4 → 2.4.5

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: f50deefb7cbd1c86b4b08b3c22d173f48a1a8da57399051247a6cd71fdc631ae
4
- data.tar.gz: 621cb083624e5fde98f425946a0efbfcf8104151140d72c9047a478fab4ca305
3
+ metadata.gz: ea9b8787072da5656c0ff4f6a2e42fa83681842bec516d07af6634798ccdb104
4
+ data.tar.gz: 9c691c8f25fffc12c055481698c90817f12ea667c622652cb55d9f74741c848d
5
5
  SHA512:
6
- metadata.gz: dbf52fd1e2efb47895308e668f120de8ae39abbd4ca51ed3a9a32f494669db317dfb3be1b5fb86bd5a770311fb175a06ed127c29a0a8296c2d6275db3f57b4b9
7
- data.tar.gz: 9379bc707799b2db5cca3d4033c3b845a802a7b811584ed057235e407a405ebc09d99a6614e7c21a2835494e0df64f06c6d02ca8e71ae6e6a02ad5ce074b8dfe
6
+ metadata.gz: 2799cfe52b7a0f01f9e07fa61fdf1a1355b8ddad2c2f6642bc731b82e25337936c1cea8c4100000e9787268ffd43504df2642faaf4a48281299403f1311692a3
7
+ data.tar.gz: a97f6b54b8a78a07a41740c01192d73ea779236ba9caeb34c5b884dd61cc74ac1256f5a728a64f2c76bdd3a260644443cd20af46ffb2b749473b715a0228cc06
@@ -607,11 +607,13 @@ module Lab
607
607
  end
608
608
 
609
609
  def orders_pending_updates(patient_id = nil, start_date: nil)
610
- Rails.logger.info('Looking for orders that need to be updated...')
610
+ Rails.logger.info("Looking for orders that need to be updated... [patient_id=#{patient_id}] [start_date=#{start_date}]")
611
611
  orders = {}
612
-
612
+ Rails.logger.info("Fetching orders without specimen...")
613
613
  orders_without_specimen(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
614
+ Rails.logger.info("Fetching orders without results...")
614
615
  orders_without_results(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
616
+ Rails.logger.info("Fetching orders without reason...")
615
617
  orders_without_reason(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
616
618
 
617
619
  orders.values
@@ -88,13 +88,40 @@ class Lab::NotificationService
88
88
  Observation.find_by(order_id: order_id)&.location_id
89
89
  end
90
90
 
91
- def notify(notification_alert, recipients)
92
- recipients.each do |recipient|
93
- next if recipient.notification_alert_recipients.exists?(alert_id: notification_alert.id)
91
+ # Was one exists? + one create per recipient (2 round trips x N users,
92
+ # sequentially) - the slow part users() and order_location() were feeding
93
+ # into. notification_alert_recipient's primary key is (alert_id, user_id),
94
+ # so a single batched insert_all does the "notify each user at most once
95
+ # per alert" dedup at the DB level instead of a round trip per user.
96
+ #
97
+ # Plain insert_all, no unique_by/on_duplicate kwargs - verified live
98
+ # against this app's Rails 8.1/mysql2 combination:
99
+ # - relation.rb's insert_all hardcodes InsertAll.execute(..., on_duplicate:
100
+ # :skip, ...) internally; on_duplicate isn't a caller-facing keyword at
101
+ # all (passing it raises "unknown keyword: :on_duplicate"), and skip-on-
102
+ # duplicate is already what plain insert_all does by default.
103
+ # - unique_by IS a caller-facing keyword, but only for adapters that need
104
+ # to be told which constraint backs the ON CONFLICT target (e.g.
105
+ # Postgres). Passing it here raises "Mysql2Adapter does not support
106
+ # :unique_by" - MySQL's own INSERT IGNORE applies to any unique/primary
107
+ # -key violation on the table, so it needs nothing extra to know that
108
+ # (alert_id, user_id) is the key to dedup against.
109
+ #
110
+ # insert_all skips AR callbacks, so uuid - the one thing the model's
111
+ # before_create/before_save would have set - is generated here;
112
+ # alert_read/cleared/date_changed are left to their column defaults.
113
+ # Chunked so one notification fan-out to a very large recipient list
114
+ # doesn't become a single giant statement.
115
+ BATCH_SIZE = 1000
116
+
117
+ def notify(notification_alert, recipients)
118
+ rows = recipients.pluck(:user_id).map do |user_id|
119
+ { alert_id: notification_alert.id, user_id: user_id, uuid: SecureRandom.uuid }
120
+ end
121
+ return if rows.empty?
94
122
 
95
- recipient.notification_alert_recipients.create(
96
- alert_id: notification_alert.id
97
- )
123
+ rows.each_slice(BATCH_SIZE) do |batch|
124
+ NotificationAlertRecipient.insert_all(batch)
98
125
  end
99
126
  end
100
127
 
@@ -25,7 +25,14 @@ module Lab
25
25
  end
26
26
 
27
27
  def find_orders_without_results(patient_id: nil)
28
- results_query = Lab::LabResult.all
28
+ # order_id IS NOT NULL matters here, not just there: SQL's NOT IN is
29
+ # poisoned by a single NULL in the subquery — `x NOT IN (1, NULL)` is
30
+ # never true for any x, because `x <> NULL` is unknown rather than
31
+ # true/false, and one unknown collapses the whole AND chain. Some
32
+ # legacy "Lab test result" observations have a NULL order_id, so
33
+ # without this filter, one such row for a patient silently zeroes out
34
+ # every order this returns for them, not just the row with the NULL.
35
+ results_query = Lab::LabResult.all.where.not(order_id: nil)
29
36
  results_query = results_query.where(person_id: patient_id) if patient_id
30
37
 
31
38
  query = Lab::LabOrder.where.not(order_id: results_query.select(:order_id))
data/lib/lab/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lab
4
- VERSION = '2.4.4'.freeze
4
+ VERSION = '2.4.5'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: his_emr_api_lab
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.4
4
+ version: 2.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elizabeth Glaser Pediatric Foundation Malawi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-24 00:00:00.000000000 Z
11
+ date: 2026-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: couchrest