openmrs_data_sanitizer 1.0.1
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 +7 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +35 -0
- data/Rakefile +4 -0
- data/app/services/openmrs_data_sanitizer/data_aggregator.rb +985 -0
- data/app/services/openmrs_data_sanitizer/data_sanitizer.rb +414 -0
- data/lib/openmrs_data_sanitizer/engine.rb +13 -0
- data/lib/openmrs_data_sanitizer/version.rb +5 -0
- data/lib/openmrs_data_sanitizer.rb +12 -0
- metadata +150 -0
@@ -0,0 +1,414 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'json'
|
5
|
+
require 'faker'
|
6
|
+
require 'fhir_models'
|
7
|
+
require 'concurrent-ruby'
|
8
|
+
|
9
|
+
# DataSanitizer
|
10
|
+
module OpenmrsDataSanitizer
|
11
|
+
# Error < StandardError; end
|
12
|
+
|
13
|
+
# rubocop:disable Metrics/ClassLength
|
14
|
+
# AWS DataSanitizer
|
15
|
+
class DataSanitizer
|
16
|
+
attr_accessor :fhir_encounters, :fhir_observations, :regimen_combinations,
|
17
|
+
:concept_names, :faker_names, :sites, :patients_json,
|
18
|
+
:fhir_medication_dispense
|
19
|
+
|
20
|
+
def initialize(sites: [])
|
21
|
+
@fhir_encounters = Concurrent::Array.new
|
22
|
+
@fhir_observations = Concurrent::Array.new
|
23
|
+
@fhir_medication_dispense = Concurrent::Array.new
|
24
|
+
@concept_names = Concurrent::Hash.new
|
25
|
+
@faker_names = Concurrent::Hash.new
|
26
|
+
@patients_json = Concurrent::Array.new
|
27
|
+
@regimen_combinations = {}
|
28
|
+
@sites = sites
|
29
|
+
load_regimen_combinations
|
30
|
+
end
|
31
|
+
|
32
|
+
def start
|
33
|
+
start_time = Time.now
|
34
|
+
Rails.logger.info("DataSanitizer started at #{start_time}")
|
35
|
+
clear_directory
|
36
|
+
process_data_request
|
37
|
+
end_time = Time.now
|
38
|
+
time_taken = (end_time - start_time) / 60
|
39
|
+
Rails.logger.info("DataSanitizer completed at #{end_time} and it took #{time_taken} minutes")
|
40
|
+
{ start_time:, end_time:, time_in_minutes: (end_time - start_time) / 60 }
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
FILE_MUTEX = Mutex.new
|
46
|
+
|
47
|
+
# ===================================
|
48
|
+
# REGION: DATA PROCESSING
|
49
|
+
# ===================================
|
50
|
+
|
51
|
+
# rubocop:disable Metrics/MethodLength
|
52
|
+
def process_data_request
|
53
|
+
queue = Queue.new
|
54
|
+
sites.each { |loc| queue << loc }
|
55
|
+
|
56
|
+
threads = Array.new(10) do
|
57
|
+
Thread.new do
|
58
|
+
until queue.empty?
|
59
|
+
loc = begin
|
60
|
+
queue.pop(true)
|
61
|
+
rescue StandardError
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
next unless loc
|
65
|
+
|
66
|
+
process_location(loc)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
threads.each(&:join)
|
72
|
+
write_data_to_files
|
73
|
+
end
|
74
|
+
|
75
|
+
def process_location(loc)
|
76
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
77
|
+
site = ::SchemaService.new.by_site(loc)&.first
|
78
|
+
return unless site
|
79
|
+
|
80
|
+
site_name = site['facility']
|
81
|
+
schema = site['schema']
|
82
|
+
|
83
|
+
OpenmrsDataSanitizer::DataAggregator.new(schema:).aggregate
|
84
|
+
|
85
|
+
process_patients(schema, site_name)
|
86
|
+
rescue StandardError => e
|
87
|
+
Rails.logger.info("Error processing location #{loc}: #{e.message}")
|
88
|
+
Rails.logger.info(e.backtrace.join("\n"))
|
89
|
+
end
|
90
|
+
end
|
91
|
+
# rubocop:enable Metrics/MethodLength
|
92
|
+
|
93
|
+
def process_patients(schema, site_name)
|
94
|
+
patients = fetch_patients(schema:)
|
95
|
+
patients_ids = patients.map { |patient| patient['person_id'].to_i }
|
96
|
+
patients.map { |patient| build_patient_json(patient, site_name) }
|
97
|
+
|
98
|
+
visits = fetch_visits(patients_ids:, schema:)
|
99
|
+
process_visits(visits:)
|
100
|
+
process_medication(schema:)
|
101
|
+
end
|
102
|
+
|
103
|
+
def write_data_to_files
|
104
|
+
write_to_file(patients_json.to_json, 'patients')
|
105
|
+
write_to_file(fhir_encounters.to_json, 'visits')
|
106
|
+
write_to_file(fhir_observations.to_json, 'observations')
|
107
|
+
write_to_file(fhir_medication_dispense.to_json, 'medications')
|
108
|
+
end
|
109
|
+
|
110
|
+
# ===================================
|
111
|
+
# REGION: REGIMEN COMBINATIONS
|
112
|
+
# ===================================
|
113
|
+
|
114
|
+
# rubocop:disable Metrics/MethodLength
|
115
|
+
def load_regimen_combinations
|
116
|
+
combinations = ActiveRecord::Base.connection.select_all <<~SQL
|
117
|
+
SELECT
|
118
|
+
moh_regimen_combination.regimen_combination_id,
|
119
|
+
GROUP_CONCAT(DISTINCT moh_regimen_combination_drug.drug_id
|
120
|
+
ORDER BY moh_regimen_combination_drug.drug_id
|
121
|
+
ASC SEPARATOR ',') AS drugs,
|
122
|
+
moh_regimen_name.name
|
123
|
+
FROM moh_regimen_combination_drug
|
124
|
+
INNER JOIN (
|
125
|
+
SELECT regimen_combination_id
|
126
|
+
FROM moh_regimen_combination_drug
|
127
|
+
) AS potential_combinations ON potential_combinations.regimen_combination_id = moh_regimen_combination_drug.regimen_combination_id
|
128
|
+
INNER JOIN moh_regimen_combination ON moh_regimen_combination.regimen_combination_id = moh_regimen_combination_drug.regimen_combination_id
|
129
|
+
INNER JOIN moh_regimen_name ON moh_regimen_name.regimen_name_id = moh_regimen_combination.regimen_name_id
|
130
|
+
GROUP BY moh_regimen_combination.regimen_combination_id;
|
131
|
+
SQL
|
132
|
+
|
133
|
+
(combinations || []).each do |combination|
|
134
|
+
regimen_combinations[combination['drugs']] = combination['name']
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# ===================================
|
139
|
+
# REGION: AWS FHIR PATIENT
|
140
|
+
# ===================================
|
141
|
+
|
142
|
+
def fetch_patients(schema:)
|
143
|
+
ActiveRecord::Base.connection.select_all <<~SQL
|
144
|
+
SELECT
|
145
|
+
p.person_id, given_name, middle_name, family_name, gender, birthdate,
|
146
|
+
phone.value phone_number, village.value village_name
|
147
|
+
FROM #{schema}.person p
|
148
|
+
INNER JOIN #{schema}.patient ON patient.patient_id = p.person_id AND p.voided = 0
|
149
|
+
INNER JOIN #{schema}.patient_program pp ON pp.patient_id = p.person_id AND pp.voided = 0 AND pp.program_id = 1
|
150
|
+
LEFT JOIN #{schema}.person_name n ON n.person_id = p.person_id AND n.voided = 0
|
151
|
+
LEFT JOIN #{schema}.person_attribute phone ON phone.person_id = p.person_id AND phone.voided = 0 AND phone.person_attribute_type_id = 12
|
152
|
+
LEFT JOIN #{schema}.person_attribute village ON village.person_id = p.person_id AND village.voided = 0 AND village.person_attribute_type_id = 19;
|
153
|
+
SQL
|
154
|
+
end
|
155
|
+
|
156
|
+
# rubocop:disable Metrics/AbcSize
|
157
|
+
def build_patient_json(patient, site_name)
|
158
|
+
patient_id = patient['person_id'].to_i
|
159
|
+
village_name = get_or_generate_faker_value(patient['village_name'], Faker::Address, :community)
|
160
|
+
cell_number = get_or_generate_faker_value(patient['phone_number'], Faker::PhoneNumber, :phone_number)
|
161
|
+
family_name = get_or_generate_faker_value(patient['family_name'], Faker::Name, :last_name)
|
162
|
+
given_name = get_or_generate_faker_value(patient['given_name'], Faker::Name, :first_name)
|
163
|
+
middle_name = get_or_generate_faker_value(patient['middle_name'], Faker::Name, :middle_name)
|
164
|
+
|
165
|
+
patients_json << FHIR::Patient.new(
|
166
|
+
id: patient_id,
|
167
|
+
identifier: [{ system: "#{site_name}_#{patient_id}", value: patient_id }],
|
168
|
+
name: [{ use: 'official', family: family_name, given: [given_name, middle_name] }],
|
169
|
+
gender: patient['gender'].match(/f/i) ? 'female' : 'male',
|
170
|
+
birthDate: patient['birthdate'],
|
171
|
+
address: [{ use: 'home', village: village_name }],
|
172
|
+
telecom: [{ system: 'phone', value: cell_number, use: 'mobile' }]
|
173
|
+
)
|
174
|
+
end
|
175
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
176
|
+
|
177
|
+
def fetch_visits(patients_ids:, schema:)
|
178
|
+
ActiveRecord::Base.connection.select_all <<~SQL
|
179
|
+
SELECT * FROM #{schema}.data_sanitizer_visits
|
180
|
+
WHERE patient_id IN(#{patients_ids.join(',')})
|
181
|
+
SQL
|
182
|
+
end
|
183
|
+
|
184
|
+
def process_visits(visits:)
|
185
|
+
(visits || []).map do |visit|
|
186
|
+
arvs_given = visit['drugs_dispensed'].to_s.split(',').map(&:to_i).sort
|
187
|
+
regimen = arvs_given.blank? ? 'N/A' : (regimen_combinations[arvs_given.join(',').squish] || 'Unknown')
|
188
|
+
aws_fhir_encounter(visit:, regimen:)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# ===================================
|
193
|
+
# REGION: AWS FHIR ENCOUNTER
|
194
|
+
# ===================================
|
195
|
+
|
196
|
+
def aws_fhir_encounter(visit:, regimen:)
|
197
|
+
patient_id = visit['patient_id'].to_i
|
198
|
+
fhir_encounters << create_fhir_encounter(patient_id, visit['visit_date'])
|
199
|
+
|
200
|
+
observations = process_indicators(visit, regimen)
|
201
|
+
create_fhir_observations(observations, patient_id, visit['visit_date'])
|
202
|
+
end
|
203
|
+
|
204
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
205
|
+
def create_fhir_encounter(patient_id, visit_date)
|
206
|
+
FHIR::Encounter.new(
|
207
|
+
id: Digest::SHA256.hexdigest(patient_id.to_s),
|
208
|
+
status: 'finished',
|
209
|
+
class: {
|
210
|
+
system: 'EGPAF Malawi EMR',
|
211
|
+
code: 'PVE',
|
212
|
+
display: 'Patient visit encounter'
|
213
|
+
},
|
214
|
+
subject: {
|
215
|
+
reference: "Patient/#{patient_id}"
|
216
|
+
},
|
217
|
+
period: {
|
218
|
+
start: visit_date,
|
219
|
+
end: visit_date
|
220
|
+
}
|
221
|
+
)
|
222
|
+
end
|
223
|
+
|
224
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/BlockLength
|
225
|
+
def process_indicators(visit, regimen)
|
226
|
+
visit.keys.map do |indicator|
|
227
|
+
next if indicator.match(/patient_id|visit_date|outcome_concept_id|outcome_end_date|other/i)
|
228
|
+
|
229
|
+
case indicator
|
230
|
+
when /weight|height/i
|
231
|
+
{
|
232
|
+
code: (indicator.match(/weight/i) ? 5089 : 5090),
|
233
|
+
display: indicator.titleize,
|
234
|
+
value: visit[indicator],
|
235
|
+
unit: (indicator.match(/weight/i) ? 'Kg' : 'cm')
|
236
|
+
}
|
237
|
+
when /adherence/i
|
238
|
+
{
|
239
|
+
code: get_concept_name(indicator.gsub('_', ' ')).concept_id,
|
240
|
+
display: indicator.titleize,
|
241
|
+
value: (visit[indicator].blank? ? visit[indicator] : visit[indicator].to_s.gsub('%', '').to_f),
|
242
|
+
unit: '%'
|
243
|
+
}
|
244
|
+
when /drugs_dispensed/i
|
245
|
+
{
|
246
|
+
code: 6882,
|
247
|
+
display: 'ARV regimen type',
|
248
|
+
value: regimen
|
249
|
+
}
|
250
|
+
else
|
251
|
+
{
|
252
|
+
code: get_concept_name(indicator.gsub('_', ' ')).concept_id,
|
253
|
+
display: indicator.titleize,
|
254
|
+
value: visit[indicator]
|
255
|
+
}
|
256
|
+
end
|
257
|
+
end.compact
|
258
|
+
end
|
259
|
+
|
260
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
261
|
+
def create_fhir_observations(observations, patient_id, visit_date)
|
262
|
+
observations.each do |obs|
|
263
|
+
next if obs.blank? || obs[:code].blank? || obs[:value].blank?
|
264
|
+
|
265
|
+
fhir_observations << FHIR::Observation.new(
|
266
|
+
status: 'final',
|
267
|
+
code: {
|
268
|
+
coding: [
|
269
|
+
{
|
270
|
+
system: 'EGPAF Malawi EMR',
|
271
|
+
code: obs[:code],
|
272
|
+
display: obs[:display]
|
273
|
+
}
|
274
|
+
]
|
275
|
+
},
|
276
|
+
subject: {
|
277
|
+
reference: "Patient/#{patient_id}"
|
278
|
+
},
|
279
|
+
encounter: {
|
280
|
+
reference: "Encounter/#{fhir_encounters.last.id}"
|
281
|
+
},
|
282
|
+
effectiveDateTime: visit_date
|
283
|
+
)
|
284
|
+
|
285
|
+
if obs[:unit]
|
286
|
+
fhir_observations.last.valueQuantity = {
|
287
|
+
value: obs[:value],
|
288
|
+
unit: obs[:unit],
|
289
|
+
system: 'EGPAF Malawi EMR',
|
290
|
+
code: obs[:code]
|
291
|
+
}
|
292
|
+
else
|
293
|
+
fhir_observations.last.valueCodeableConcept = {
|
294
|
+
coding: [
|
295
|
+
{
|
296
|
+
system: 'EGPAF Malawi EMR',
|
297
|
+
code: obs[:code],
|
298
|
+
display: (if obs[:value] == '1065'
|
299
|
+
'Yes'
|
300
|
+
else
|
301
|
+
obs[:value] == '1066' ? 'No' : obs[:value]
|
302
|
+
end)
|
303
|
+
}
|
304
|
+
]
|
305
|
+
}
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/BlockLength, Metrics/PerceivedComplexity
|
310
|
+
|
311
|
+
# ===================================
|
312
|
+
# REGION: AWS FHIR MEDICATIONS
|
313
|
+
# ===================================
|
314
|
+
|
315
|
+
def process_medication(schema:)
|
316
|
+
orders = fetch_medication(schema:)
|
317
|
+
create_fhir_medications(orders:)
|
318
|
+
end
|
319
|
+
|
320
|
+
def fetch_medication(schema:)
|
321
|
+
ActiveRecord::Base.connection.select_all <<~SQL
|
322
|
+
SELECT * FROM #{schema}.data_sanitizer_arv_orders
|
323
|
+
SQL
|
324
|
+
end
|
325
|
+
|
326
|
+
def create_fhir_medications(orders:)
|
327
|
+
fhir_medication_dispense << (orders || []).map do |order|
|
328
|
+
patient_id = order['patient_id'].to_i
|
329
|
+
order_id = order['order_id'].to_i
|
330
|
+
encounter_id = order['encounter_id'].to_i
|
331
|
+
FHIR::MedicationDispense.new(
|
332
|
+
identifier: {
|
333
|
+
value: order_id
|
334
|
+
},
|
335
|
+
status: 'completed',
|
336
|
+
patient: {
|
337
|
+
reference: encounter_id
|
338
|
+
},
|
339
|
+
medication: {
|
340
|
+
code: {
|
341
|
+
text: order['drug_name'],
|
342
|
+
coding: [
|
343
|
+
{
|
344
|
+
system: 'EGPAF Malawi EMR',
|
345
|
+
code: order['drug_id'],
|
346
|
+
display: order['drug_name']
|
347
|
+
}
|
348
|
+
]
|
349
|
+
}
|
350
|
+
},
|
351
|
+
dispensed: {
|
352
|
+
quantity: {
|
353
|
+
value: order['quantity'].to_f,
|
354
|
+
unit: order['units']
|
355
|
+
},
|
356
|
+
type: {
|
357
|
+
text: order['units']
|
358
|
+
},
|
359
|
+
dateTime: order['start_date']
|
360
|
+
},
|
361
|
+
dosageInstruction: [
|
362
|
+
{
|
363
|
+
text: order['instructions']
|
364
|
+
}
|
365
|
+
],
|
366
|
+
dispense: {
|
367
|
+
validityPeriod: {
|
368
|
+
start: order['start_date'],
|
369
|
+
end: order['runout_date']
|
370
|
+
}
|
371
|
+
}
|
372
|
+
)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
# ===================================
|
377
|
+
# Helper methods
|
378
|
+
# ===================================
|
379
|
+
|
380
|
+
def get_or_generate_faker_value(attribute, faker_module, faker_method)
|
381
|
+
return '' if attribute.blank?
|
382
|
+
|
383
|
+
@faker_names[attribute] ||= faker_module.send(faker_method)
|
384
|
+
end
|
385
|
+
|
386
|
+
def get_concept_name(name)
|
387
|
+
concept_names[name] ||= ConceptName.find_by_name(name)
|
388
|
+
end
|
389
|
+
|
390
|
+
def clear_directory
|
391
|
+
dir_path = Rails.root.join('log/openmrs_data_sanitizer')
|
392
|
+
return unless Dir.exist?(dir_path)
|
393
|
+
|
394
|
+
FileUtils.rm_rf(dir_path)
|
395
|
+
end
|
396
|
+
|
397
|
+
def write_to_file(json_file, file_name)
|
398
|
+
dir_path = Rails.root.join('log/openmrs_data_sanitizer')
|
399
|
+
file_path = dir_path.join("#{file_name}.json")
|
400
|
+
|
401
|
+
# Ensure the directory exists
|
402
|
+
Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
|
403
|
+
|
404
|
+
# Use the mutex to handle concurrent writes
|
405
|
+
FILE_MUTEX.synchronize do
|
406
|
+
File.open(file_path, 'a') do |out_file|
|
407
|
+
out_file.puts(json_file)
|
408
|
+
puts "Created file: #{file_path}"
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
# rubocop:enable Metrics/ClassLength
|
414
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenmrsDataSanitizer
|
4
|
+
# Engine class
|
5
|
+
class Engine < ::Rails::Engine
|
6
|
+
isolate_namespace OpenmrsDataSanitizer
|
7
|
+
config.generators.api_only = true
|
8
|
+
|
9
|
+
config.generators do |g|
|
10
|
+
g.test_framework :rspec
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Path: lib/malawi_hiv_program_reports.rb
|
4
|
+
require 'openmrs_data_sanitizer/version'
|
5
|
+
require 'openmrs_data_sanitizer/engine'
|
6
|
+
|
7
|
+
# main module of the gem
|
8
|
+
module OpenmrsDataSanitizer
|
9
|
+
def self.hi
|
10
|
+
puts 'Welcome to MalawiHivProgramReports!'
|
11
|
+
end
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: openmrs_data_sanitizer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mwatha
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-08-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: concurrent-ruby
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faker
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.20'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.20'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: fhir_models
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mysql2
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.5.6
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.5.6
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 7.1.3
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 7.1.3.4
|
79
|
+
type: :runtime
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - "~>"
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 7.1.3
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 7.1.3.4
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: rspec
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '3.13'
|
96
|
+
type: :runtime
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '3.13'
|
103
|
+
description: This gem will mask all patient identifyable data before exporting to
|
104
|
+
AWS FHIR API
|
105
|
+
email:
|
106
|
+
- mwathabwanali@gmail.com
|
107
|
+
executables: []
|
108
|
+
extensions: []
|
109
|
+
extra_rdoc_files:
|
110
|
+
- README.md
|
111
|
+
files:
|
112
|
+
- CHANGELOG.md
|
113
|
+
- Gemfile
|
114
|
+
- LICENSE.txt
|
115
|
+
- README.md
|
116
|
+
- Rakefile
|
117
|
+
- app/services/openmrs_data_sanitizer/data_aggregator.rb
|
118
|
+
- app/services/openmrs_data_sanitizer/data_sanitizer.rb
|
119
|
+
- lib/openmrs_data_sanitizer.rb
|
120
|
+
- lib/openmrs_data_sanitizer/engine.rb
|
121
|
+
- lib/openmrs_data_sanitizer/version.rb
|
122
|
+
homepage: https://github.com/egpaf-global/openmrs_data_sanitizer
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
metadata:
|
126
|
+
homepage_uri: https://github.com/egpaf-global/openmrs_data_sanitizer
|
127
|
+
source_code_uri: https://github.com/egpaf-global/openmrs_data_sanitizer
|
128
|
+
changelog_uri: https://github.com/egpaf-global/openmrs_data_sanitizer/blob/master/CHANGELOG.md
|
129
|
+
rubygems_mfa_required: 'true'
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 3.2.0
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
requirements: []
|
145
|
+
rubygems_version: 3.4.5
|
146
|
+
signing_key:
|
147
|
+
specification_version: 4
|
148
|
+
summary: This gem will mask all patient identifyable data before exporting to AWS
|
149
|
+
FHIR API
|
150
|
+
test_files: []
|