openchs-models 1.32.41 → 1.32.43

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 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
- const findMediaObservations = (...observations) => _lodash.default.filter(_lodash.default.flatten(observations), observation => _Concept.default.dataType.Media.includes(observation.concept.datatype));
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
- const observation = _lodash.default.find(this.observations, observation => observation.concept.uuid === conceptUUID);
527
+ let updated = false; // Iterate through all observations
488
528
 
489
- if (observation) {
490
- const valueWrapper = observation.getValueWrapper();
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
- if (observation.concept.datatype === _Concept.default.dataType.ImageV2) {
493
- const mediaObjects = JSON.parse(valueWrapper.getValue());
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
- const newAnswers = _lodash.default.map(mediaObjects, mediaObject => {
496
- if (mediaObject.uri === oldValue) {
497
- mediaObject.uri = newValue;
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
- return mediaObject;
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
- } else if (valueWrapper.isMultipleCoded) {
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 < 0) return; // due to race condition the old value might have been removed
590
+ if (oldValueIndex >= 0) {
591
+ const newAnswers = _lodash.default.reject(answers, answer => answer === oldValue);
510
592
 
511
- const newAnswers = _lodash.default.reject(answers, answer => answer === oldValue);
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
- newAnswers.splice(oldValueIndex, 0, newValue);
514
- observation.valueJSON = new _MultipleCodedValues.default(newAnswers);
515
- } else {
516
- observation.valueJSON = new _SingleCodedValue.default(newValue);
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) {
package/dist/Schema.js CHANGED
@@ -283,7 +283,7 @@ function createRealmConfig() {
283
283
  return doCompact;
284
284
  },
285
285
  //order is important, should be arranged according to the dependency
286
- schemaVersion: 200,
286
+ schemaVersion: 201,
287
287
  onMigration: function (oldDB, newDB) {
288
288
  console.log("[AvniModels.Schema]", `Running migration with old schema version: ${oldDB.schemaVersion} and new schema version: ${newDB.schemaVersion}`);
289
289
  if (oldDB.schemaVersion === VersionWithEmbeddedMigrationProblem) throw new Error(`Update from schema version ${VersionWithEmbeddedMigrationProblem} is not allowed. Please uninstall and install app.`);
@@ -972,7 +972,7 @@ function createRealmConfig() {
972
972
  });
973
973
  }
974
974
 
975
- if (oldDB.schemaVersion < 200) {
975
+ if (oldDB.schemaVersion < 201) {
976
976
  _lodash.default.forEach(newDB.objects("Concept"), concept => {
977
977
  concept.mediaType = null;
978
978
  concept.mediaUrl = null;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "openchs-models",
3
3
  "description": "OpenCHS data model to be used by front end clients",
4
- "version": "1.32.41",
4
+ "version": "1.32.43",
5
5
  "private": false,
6
6
  "repository": {
7
7
  "type": "git",