comparison OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp @ 4938:f630796a59b1 more-tags

ExpandResource now able to return computed tags (like ModalitiesInStudies)
author Alain Mazy <am@osimis.io>
date Mon, 14 Mar 2022 16:44:00 +0100
parents 8422e4f99a18
children e8a2e145c80e
comparison
equal deleted inserted replaced
4937:3f9b9865c8cc 4938:f630796a59b1
758 { 758 {
759 return false; 759 return false;
760 } 760 }
761 } 761 }
762 762
763 static void ComputeSeriesTags(DicomMap& result,
764 const std::list<std::string>& children,
765 const std::set<DicomTag>& requestedTags)
766 {
767 if (requestedTags.count(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES) > 0)
768 {
769 result.SetValue(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES,
770 boost::lexical_cast<std::string>(children.size()), false);
771 }
772 }
773
774 static void ComputeStudyTags(DicomMap& result,
775 ReadOnlyTransaction& transaction,
776 const std::string& studyPublicId,
777 int64_t studyInternalId,
778 const std::set<DicomTag>& requestedTags)
779 {
780 std::list<int64_t> seriesInternalIds;
781 std::list<int64_t> instancesInternalIds;
782
783 transaction.GetChildrenInternalId(seriesInternalIds, studyInternalId);
784
785 if (requestedTags.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES) > 0)
786 {
787 result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES,
788 boost::lexical_cast<std::string>(seriesInternalIds.size()), false);
789 }
790
791 if (requestedTags.count(DICOM_TAG_MODALITIES_IN_STUDY) > 0)
792 {
793 std::set<std::string> values;
794
795 for (std::list<int64_t>::const_iterator
796 it = seriesInternalIds.begin(); it != seriesInternalIds.end(); ++it)
797 {
798 if (requestedTags.count(DICOM_TAG_MODALITIES_IN_STUDY) > 0)
799 {
800 DicomMap tags;
801 transaction.GetMainDicomTags(tags, *it);
802
803 const DicomValue* value = tags.TestAndGetValue(DICOM_TAG_MODALITY);
804
805 if (value != NULL &&
806 !value->IsNull() &&
807 !value->IsBinary())
808 {
809 values.insert(value->GetContent());
810 }
811 }
812 }
813
814 std::string modalities;
815 Toolbox::JoinStrings(modalities, values, "\\");
816 result.SetValue(DICOM_TAG_MODALITIES_IN_STUDY, modalities, false);
817 }
818
819 if (requestedTags.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) > 0
820 || requestedTags.count(DICOM_TAG_SOP_CLASSES_IN_STUDY) > 0)
821 {
822 for (std::list<int64_t>::const_iterator
823 it = seriesInternalIds.begin(); it != seriesInternalIds.end(); ++it)
824 {
825 std::list<int64_t> seriesInstancesIds;
826 transaction.GetChildrenInternalId(seriesInstancesIds, *it);
827
828 instancesInternalIds.splice(instancesInternalIds.end(), seriesInstancesIds);
829 }
830
831 if (requestedTags.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) > 0)
832 {
833 result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES,
834 boost::lexical_cast<std::string>(instancesInternalIds.size()), false);
835 }
836
837 if (requestedTags.count(DICOM_TAG_SOP_CLASSES_IN_STUDY) > 0)
838 {
839 std::set<std::string> values;
840
841 for (std::list<int64_t>::const_iterator
842 it = instancesInternalIds.begin(); it != instancesInternalIds.end(); ++it)
843 {
844 std::map<MetadataType, std::string> instanceMetadata;
845 // Extract the metadata
846 transaction.GetAllMetadata(instanceMetadata, *it);
847
848 std::string value;
849 if (!LookupStringMetadata(value, instanceMetadata, MetadataType_Instance_SopClassUid))
850 {
851 throw OrthancException(ErrorCode_InternalError, "Unable to get the SOP Class Uid from an instance of the study " + studyPublicId + " because the instance has been saved with an old version of Orthanc (< 1.2.0). You should POST to /studies/" + studyPublicId + "/reconstruct to avoid this error");
852 }
853
854 values.insert(value);
855 }
856
857 std::string sopClassUids;
858 Toolbox::JoinStrings(sopClassUids, values, "\\");
859 result.SetValue(DICOM_TAG_SOP_CLASSES_IN_STUDY, sopClassUids, false);
860 }
861 }
862 }
863
864 static void ComputePatientTags(DicomMap& result,
865 ReadOnlyTransaction& transaction,
866 const std::string& patientPublicId,
867 int64_t patientInternalId,
868 const std::set<DicomTag>& requestedTags)
869 {
870 std::list<int64_t> studiesInternalIds;
871 std::list<int64_t> seriesInternalIds;
872 std::list<int64_t> instancesInternalIds;
873
874 bool hasNbRelatedStudies = requestedTags.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES) > 0;
875 bool hasNbRelatedSeries = requestedTags.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES) > 0;
876 bool hasNbRelatedInstances = requestedTags.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES) > 0;
877
878 transaction.GetChildrenInternalId(studiesInternalIds, patientInternalId);
879
880 if (hasNbRelatedStudies)
881 {
882 result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES,
883 boost::lexical_cast<std::string>(studiesInternalIds.size()), false);
884 }
885
886 if (hasNbRelatedSeries || hasNbRelatedInstances)
887 {
888 for (std::list<int64_t>::const_iterator
889 it = studiesInternalIds.begin(); it != studiesInternalIds.end(); ++it)
890 {
891 std::list<int64_t> thisSeriesIds;
892 transaction.GetChildrenInternalId(thisSeriesIds, *it);
893 seriesInternalIds.splice(seriesInternalIds.end(), thisSeriesIds);
894
895 if (hasNbRelatedInstances)
896 {
897 for (std::list<int64_t>::const_iterator
898 it2 = seriesInternalIds.begin(); it2 != seriesInternalIds.end(); ++it2)
899 {
900 std::list<int64_t> thisInstancesIds;
901 transaction.GetChildrenInternalId(thisInstancesIds, *it2);
902 instancesInternalIds.splice(instancesInternalIds.end(), thisInstancesIds);
903 }
904 }
905 }
906
907 if (hasNbRelatedSeries)
908 {
909 result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES,
910 boost::lexical_cast<std::string>(seriesInternalIds.size()), false);
911 }
912
913 if (hasNbRelatedInstances)
914 {
915 result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES,
916 boost::lexical_cast<std::string>(instancesInternalIds.size()), false);
917 }
918 }
919 }
763 920
764 public: 921 public:
765 virtual void ApplyTuple(ReadOnlyTransaction& transaction, 922 virtual void ApplyTuple(ReadOnlyTransaction& transaction,
766 const Tuple& tuple) ORTHANC_OVERRIDE 923 const Tuple& tuple) ORTHANC_OVERRIDE
767 { 924 {
916 target.tags_.Merge(parentTags); 1073 target.tags_.Merge(parentTags);
917 } 1074 }
918 1075
919 currentInternalId = currentParentId; 1076 currentInternalId = currentParentId;
920 } 1077 }
1078
1079 { // handle the tags that must be rebuilt because they are not saved in DB
1080 if (target.type_ == ResourceType_Study && (
1081 target.missingRequestedTags_.count(DICOM_TAG_MODALITIES_IN_STUDY) > 0
1082 || target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) > 0
1083 || target.missingRequestedTags_.count(DICOM_TAG_SOP_CLASSES_IN_STUDY) > 0
1084 || target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES) > 0
1085 ))
1086 {
1087 ComputeStudyTags(target.tags_, transaction, target.id_, internalId, requestedTags);
1088 }
1089
1090 if (target.type_ == ResourceType_Series
1091 && target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES) > 0)
1092 {
1093 ComputeSeriesTags(target.tags_, target.childrenIds_, requestedTags);
1094 }
1095
1096 if (target.type_ == ResourceType_Patient && (
1097 target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES) > 0
1098 || target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES) > 0
1099 || target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES) > 0
1100 ))
1101 {
1102 ComputePatientTags(target.tags_, transaction, target.id_, internalId, requestedTags);
1103 }
1104 }
1105
921 } 1106 }
922 1107
923 std::string tmp; 1108 std::string tmp;
924 1109
925 if (LookupStringMetadata(tmp, target.metadata_, MetadataType_AnonymizedFrom)) 1110 if (LookupStringMetadata(tmp, target.metadata_, MetadataType_AnonymizedFrom))