openchs-models 1.32.41 → 1.32.42
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.
- package/dist/Media.js +77 -1
- package/dist/ObservationsHolder.js +193 -24
- package/package.json +1 -1
package/dist/Media.js
CHANGED
|
@@ -11,6 +11,82 @@ var _Concept = _interopRequireDefault(require("./Concept"));
|
|
|
11
11
|
|
|
12
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// Helper to check if an observation is a media observation
|
|
15
|
+
const isMediaObservation = observation => {
|
|
16
|
+
if (!observation || !observation.concept) return false;
|
|
17
|
+
return _Concept.default.dataType.Media.includes(observation.concept.datatype);
|
|
18
|
+
}; // Helper to collect media observations from an array of observations
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
const collectMediaObservations = observations => {
|
|
22
|
+
return _lodash.default.filter(observations, isMediaObservation);
|
|
23
|
+
}; // Helper to process observations in a question group
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
const processQuestionGroup = questionGroup => {
|
|
27
|
+
// Get observations inside the question group
|
|
28
|
+
const groupObservations = questionGroup.getValue && Array.isArray(questionGroup.getValue()) ? questionGroup.getValue() : []; // Return media observations inside the question group
|
|
29
|
+
|
|
30
|
+
return collectMediaObservations(groupObservations);
|
|
31
|
+
}; // Helper to process observations in a repeatable question group
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
const processRepeatableQuestionGroup = repeatableQuestionGroup => {
|
|
35
|
+
// Get all question groups from the repeatable question group
|
|
36
|
+
const allGroups = repeatableQuestionGroup.getAllQuestionGroupObservations && repeatableQuestionGroup.getAllQuestionGroupObservations() || []; // Process each question group and collect all media observations
|
|
37
|
+
|
|
38
|
+
return _lodash.default.flatten(allGroups.map(group => processQuestionGroup(group)));
|
|
39
|
+
}; // Process an individual observation and its nested structure if applicable
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
const processObservation = observation => {
|
|
43
|
+
if (!observation) return [];
|
|
44
|
+
const result = []; // Case 1: Direct media observation
|
|
45
|
+
|
|
46
|
+
if (isMediaObservation(observation)) {
|
|
47
|
+
result.push(observation);
|
|
48
|
+
} // Check for nested observations in value wrapper
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const valueWrapper = observation.getValueWrapper && observation.getValueWrapper();
|
|
53
|
+
|
|
54
|
+
if (!valueWrapper) {
|
|
55
|
+
return result;
|
|
56
|
+
} // Case 2a: Regular Question Group
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if (!valueWrapper.isRepeatable || !valueWrapper.isRepeatable()) {
|
|
60
|
+
result.push(...processQuestionGroup(valueWrapper));
|
|
61
|
+
} // Case 2b: Repeatable Question Group
|
|
62
|
+
else {
|
|
63
|
+
result.push(...processRepeatableQuestionGroup(valueWrapper));
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
// Silently handle parsing errors or invalid structures
|
|
67
|
+
console.log(`[INFO] Error processing observation: ${error.message}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return result;
|
|
71
|
+
}; // Main function to find all media observations
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
const findMediaObservations = (...observations) => {
|
|
75
|
+
console.log(`[INFO] Finding media observations in ${observations.length} observation arrays`); // Handle null or undefined input
|
|
76
|
+
|
|
77
|
+
if (!observations || !observations.length) return []; // Filter out null or undefined values
|
|
78
|
+
|
|
79
|
+
const validObservations = observations.filter(obs => obs != null); // Process all input observation arrays
|
|
80
|
+
|
|
81
|
+
const flattenedObservations = _lodash.default.flatten(validObservations); // Handle empty array
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
if (!flattenedObservations || !flattenedObservations.length) return []; // Process each observation and collect results
|
|
85
|
+
|
|
86
|
+
const result = _lodash.default.flatten(flattenedObservations.map(processObservation).filter(item => item != null));
|
|
87
|
+
|
|
88
|
+
console.log(`[INFO] Found ${result.length} media observations`);
|
|
89
|
+
return result;
|
|
90
|
+
};
|
|
15
91
|
|
|
16
92
|
exports.findMediaObservations = findMediaObservations;
|
|
@@ -43,6 +43,49 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
|
|
43
43
|
|
|
44
44
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
45
45
|
|
|
46
|
+
// Helper function to find media observation by value
|
|
47
|
+
const findMediaObservationByValue = (observations, targetValue) => {
|
|
48
|
+
if (!observations || !Array.isArray(observations)) return null;
|
|
49
|
+
return _lodash.default.find(observations, obs => {
|
|
50
|
+
// Check direct value
|
|
51
|
+
if (obs.getValue && obs.getValue() === targetValue) return true; // Check coded values (for MultipleCodedValues)
|
|
52
|
+
|
|
53
|
+
const valueJSON = obs.valueJSON;
|
|
54
|
+
|
|
55
|
+
if (valueJSON && valueJSON.answer && Array.isArray(valueJSON.answer)) {
|
|
56
|
+
return valueJSON.answer.includes(targetValue);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return false;
|
|
60
|
+
});
|
|
61
|
+
}; // Helper function to update media value
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
const updateMediaValue = (mediaObs, oldVal, newVal) => {
|
|
65
|
+
if (!mediaObs) return false; // For coded values, we need to update the array content
|
|
66
|
+
|
|
67
|
+
if (mediaObs.valueJSON && mediaObs.valueJSON.answer && Array.isArray(mediaObs.valueJSON.answer)) {
|
|
68
|
+
const answerIndex = mediaObs.valueJSON.answer.indexOf(oldVal);
|
|
69
|
+
|
|
70
|
+
if (answerIndex >= 0) {
|
|
71
|
+
mediaObs.valueJSON.answer[answerIndex] = newVal;
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
// Regular value update
|
|
76
|
+
mediaObs.setValue(mediaObs.concept.getValueWrapperFor(newVal));
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return false;
|
|
81
|
+
}; // Process each question group observation
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
const processQuestionGroupObservations = (observations, oldVal, newVal) => {
|
|
85
|
+
const mediaObs = findMediaObservationByValue(observations, oldVal);
|
|
86
|
+
return mediaObs ? updateMediaValue(mediaObs, oldVal, newVal) : false;
|
|
87
|
+
};
|
|
88
|
+
|
|
46
89
|
class ObservationsHolder {
|
|
47
90
|
constructor(observations) {
|
|
48
91
|
this.observations = observations;
|
|
@@ -472,50 +515,176 @@ class ObservationsHolder {
|
|
|
472
515
|
|
|
473
516
|
|
|
474
517
|
updateObservationBasedOnValue(oldValue, newValue) {
|
|
518
|
+
// Try to find at top level first
|
|
475
519
|
const observation = this.findObservationByValue(oldValue);
|
|
476
520
|
|
|
477
521
|
if (observation) {
|
|
478
522
|
observation.setValue(observation.concept.getValueWrapperFor(newValue));
|
|
479
|
-
|
|
480
|
-
|
|
523
|
+
return true;
|
|
524
|
+
} // Search in nested structures if not found at top level
|
|
481
525
|
|
|
482
|
-
replaceMediaObservation(oldValue, newValue, conceptUUID) {
|
|
483
|
-
if (_lodash.default.isNil(conceptUUID)) {
|
|
484
|
-
return this.updateObservationBasedOnValue(oldValue, newValue);
|
|
485
|
-
}
|
|
486
526
|
|
|
487
|
-
|
|
527
|
+
let updated = false; // Iterate through all observations
|
|
488
528
|
|
|
489
|
-
|
|
490
|
-
|
|
529
|
+
_lodash.default.forEach(this.observations, obs => {
|
|
530
|
+
// Skip non-question group observations
|
|
531
|
+
if (obs.concept.datatype !== _Concept.default.dataType.QuestionGroup) return;
|
|
532
|
+
const valueWrapper = obs.getValueWrapper && obs.getValueWrapper();
|
|
533
|
+
if (!valueWrapper) return; // Handle RepeatableQuestionGroup
|
|
534
|
+
|
|
535
|
+
if (valueWrapper.isRepeatable && valueWrapper.isRepeatable()) {
|
|
536
|
+
const allGroups = valueWrapper.getAllQuestionGroupObservations && valueWrapper.getAllQuestionGroupObservations();
|
|
491
537
|
|
|
492
|
-
|
|
493
|
-
|
|
538
|
+
if (allGroups && allGroups.length) {
|
|
539
|
+
// Check each group in the repeatable question group
|
|
540
|
+
allGroups.forEach(group => {
|
|
541
|
+
const groupObservations = group.getValue && group.getValue();
|
|
494
542
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
543
|
+
if (processQuestionGroupObservations(groupObservations, oldValue, newValue)) {
|
|
544
|
+
updated = true;
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
} // Handle regular QuestionGroup
|
|
549
|
+
else {
|
|
550
|
+
const groupObservations = valueWrapper.getValue && valueWrapper.getValue();
|
|
551
|
+
|
|
552
|
+
if (processQuestionGroupObservations(groupObservations, oldValue, newValue)) {
|
|
553
|
+
updated = true;
|
|
498
554
|
}
|
|
555
|
+
}
|
|
556
|
+
});
|
|
499
557
|
|
|
500
|
-
|
|
501
|
-
|
|
558
|
+
return updated;
|
|
559
|
+
} // Helper method to update media value in an observation
|
|
502
560
|
|
|
561
|
+
|
|
562
|
+
_updateMediaValueInObservation(observation, oldValue, newValue) {
|
|
563
|
+
if (!observation) return false;
|
|
564
|
+
const valueWrapper = observation.getValueWrapper && observation.getValueWrapper();
|
|
565
|
+
if (!valueWrapper) return false; // Handle ImageV2 type
|
|
566
|
+
|
|
567
|
+
if (observation.concept.datatype === _Concept.default.dataType.ImageV2) {
|
|
568
|
+
const mediaObjects = JSON.parse(valueWrapper.getValue());
|
|
569
|
+
let updated = false;
|
|
570
|
+
|
|
571
|
+
const newAnswers = _lodash.default.map(mediaObjects, mediaObject => {
|
|
572
|
+
if (mediaObject.uri === oldValue) {
|
|
573
|
+
mediaObject.uri = newValue;
|
|
574
|
+
updated = true;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
return mediaObject;
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
if (updated) {
|
|
503
581
|
observation.valueJSON = new _PrimitiveValue.default(JSON.stringify(newAnswers), _Concept.default.dataType.ImageV2);
|
|
504
|
-
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
584
|
+
} // Handle multiple coded values
|
|
585
|
+
else if (valueWrapper.isMultipleCoded) {
|
|
505
586
|
const answers = valueWrapper.getValue();
|
|
506
587
|
|
|
507
588
|
const oldValueIndex = _lodash.default.indexOf(answers, oldValue);
|
|
508
589
|
|
|
509
|
-
if (oldValueIndex
|
|
590
|
+
if (oldValueIndex >= 0) {
|
|
591
|
+
const newAnswers = _lodash.default.reject(answers, answer => answer === oldValue);
|
|
510
592
|
|
|
511
|
-
|
|
593
|
+
newAnswers.splice(oldValueIndex, 0, newValue);
|
|
594
|
+
observation.valueJSON = new _MultipleCodedValues.default(newAnswers);
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
} // Handle single coded value
|
|
598
|
+
else if (valueWrapper.getValue() === oldValue) {
|
|
599
|
+
observation.valueJSON = new _SingleCodedValue.default(newValue);
|
|
600
|
+
return true;
|
|
601
|
+
}
|
|
512
602
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
603
|
+
return false;
|
|
604
|
+
} // Helper to find and update media in question group
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
_updateMediaInQuestionGroup(questionGroup, conceptUUID, oldValue, newValue) {
|
|
608
|
+
if (!questionGroup || !questionGroup.getValue) return false;
|
|
609
|
+
const groupObservations = questionGroup.getValue();
|
|
610
|
+
if (!groupObservations || !Array.isArray(groupObservations)) return false; // Find media observation either by concept UUID or by value
|
|
611
|
+
|
|
612
|
+
const mediaObs = _lodash.default.find(groupObservations, obs => obs.concept.uuid === conceptUUID || _Concept.default.dataType.Media.includes(obs.concept.datatype) && obs.getValue && obs.getValue() === oldValue); // Update if found
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
return this._updateMediaValueInObservation(mediaObs, oldValue, newValue);
|
|
616
|
+
} // Helper to find and update media in repeatable question group
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
_updateMediaInRepeatableQuestionGroup(repeatableGroup, conceptUUID, oldValue, newValue) {
|
|
620
|
+
if (!repeatableGroup || !repeatableGroup.getAllQuestionGroupObservations) return false;
|
|
621
|
+
const allGroups = repeatableGroup.getAllQuestionGroupObservations();
|
|
622
|
+
if (!allGroups || !allGroups.length) return false; // Check each group in the repeatable question group
|
|
623
|
+
|
|
624
|
+
let updated = false;
|
|
625
|
+
allGroups.forEach(group => {
|
|
626
|
+
if (this._updateMediaInQuestionGroup(group, conceptUUID, oldValue, newValue)) {
|
|
627
|
+
updated = true;
|
|
517
628
|
}
|
|
518
|
-
}
|
|
629
|
+
});
|
|
630
|
+
return updated;
|
|
631
|
+
} // Helper to process a question group (regular or repeatable) and update media within it
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
_processQuestionGroupWrapper(wrapper, conceptUUID, oldValue, newValue, sourceName) {
|
|
635
|
+
if (!wrapper) return false; // Determine if it's a repeatable question group or regular question group
|
|
636
|
+
|
|
637
|
+
const isRepeatable = wrapper.isRepeatable && wrapper.isRepeatable(); // Process the appropriate group type
|
|
638
|
+
|
|
639
|
+
return isRepeatable ? this._updateMediaInRepeatableQuestionGroup(wrapper, conceptUUID, oldValue, newValue) : this._updateMediaInQuestionGroup(wrapper, conceptUUID, oldValue, newValue);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
replaceMediaObservation(oldValue, newValue, conceptUUID) {
|
|
643
|
+
console.log(`[INFO] Replacing media: ${oldValue} → ${newValue}`); // Since conceptUUID is always provided in practice, optimize for that case first
|
|
644
|
+
// Try to find direct top-level observation with matching concept UUID
|
|
645
|
+
|
|
646
|
+
const directObservation = _lodash.default.find(this.observations, obs => obs.concept.uuid === conceptUUID);
|
|
647
|
+
|
|
648
|
+
if (directObservation) {
|
|
649
|
+
// Direct media observation
|
|
650
|
+
if (_Concept.default.dataType.Media.includes(directObservation.concept.datatype)) {
|
|
651
|
+
if (this._updateMediaValueInObservation(directObservation, oldValue, newValue)) {
|
|
652
|
+
console.log(`[INFO] Updated media in direct observation`);
|
|
653
|
+
return true;
|
|
654
|
+
}
|
|
655
|
+
} // Question Group containing the media
|
|
656
|
+
else if (directObservation.concept.datatype === _Concept.default.dataType.QuestionGroup) {
|
|
657
|
+
const valueWrapper = directObservation.getValueWrapper();
|
|
658
|
+
|
|
659
|
+
if (this._processQuestionGroupWrapper(valueWrapper, conceptUUID, oldValue, newValue)) {
|
|
660
|
+
console.log(`[INFO] Updated media in question group`);
|
|
661
|
+
return true;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
} // Check nested structures (this works both with and without conceptUUID)
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
let updated = false;
|
|
668
|
+
|
|
669
|
+
_lodash.default.forEach(this.observations, obs => {
|
|
670
|
+
// Only process question groups
|
|
671
|
+
if (obs.concept.datatype !== _Concept.default.dataType.QuestionGroup) return;
|
|
672
|
+
const valueWrapper = obs.getValueWrapper && obs.getValueWrapper();
|
|
673
|
+
if (!valueWrapper) return;
|
|
674
|
+
|
|
675
|
+
if (this._processQuestionGroupWrapper(valueWrapper, conceptUUID, oldValue, newValue)) {
|
|
676
|
+
updated = true;
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
if (updated) {
|
|
681
|
+
console.log(`[INFO] Updated media in nested structure`);
|
|
682
|
+
return true;
|
|
683
|
+
} // As a fallback, use value-based replacement if we couldn't find it by concept
|
|
684
|
+
// This ensures backward compatibility and handles edge cases
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
return this.updateObservationBasedOnValue(oldValue, newValue);
|
|
519
688
|
}
|
|
520
689
|
|
|
521
690
|
toString(I18n) {
|