Mercurial > hg > orthanc
diff OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp @ 4940:304514ce84ee more-tags
tools/find + C-Find + list-resources now all using the same code (ExpandResource) to build 'computed tags'
author | Alain Mazy <am@osimis.io> |
---|---|
date | Tue, 15 Mar 2022 15:57:21 +0100 |
parents | e8a2e145c80e |
children | 8fba26292a9f |
line wrap: on
line diff
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Tue Mar 15 09:09:52 2022 +0100 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Tue Mar 15 15:57:21 2022 +0100 @@ -713,10 +713,11 @@ bool StatelessDatabaseOperations::ExpandResource(ExpandedResource& target, const std::string& publicId, ResourceType level, - const std::set<DicomTag>& requestedTags) + const std::set<DicomTag>& requestedTags, + ExpandResourceDbFlags expandFlags) { - class Operations : public ReadOnlyOperationsT5< - bool&, ExpandedResource&, const std::string&, ResourceType, const std::set<DicomTag>&> + class Operations : public ReadOnlyOperationsT6< + bool&, ExpandedResource&, const std::string&, ResourceType, const std::set<DicomTag>&, ExpandResourceDbFlags> { private: @@ -759,163 +760,6 @@ } } - static void ComputeSeriesTags(DicomMap& result, - const std::list<std::string>& children, - const std::set<DicomTag>& requestedTags) - { - if (requestedTags.count(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES) > 0) - { - result.SetValue(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES, - boost::lexical_cast<std::string>(children.size()), false); - } - } - - static void ComputeStudyTags(DicomMap& result, - ReadOnlyTransaction& transaction, - const std::string& studyPublicId, - int64_t studyInternalId, - const std::set<DicomTag>& requestedTags) - { - std::list<int64_t> seriesInternalIds; - std::list<int64_t> instancesInternalIds; - - transaction.GetChildrenInternalId(seriesInternalIds, studyInternalId); - - if (requestedTags.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES) > 0) - { - result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES, - boost::lexical_cast<std::string>(seriesInternalIds.size()), false); - } - - if (requestedTags.count(DICOM_TAG_MODALITIES_IN_STUDY) > 0) - { - std::set<std::string> values; - - for (std::list<int64_t>::const_iterator - it = seriesInternalIds.begin(); it != seriesInternalIds.end(); ++it) - { - if (requestedTags.count(DICOM_TAG_MODALITIES_IN_STUDY) > 0) - { - DicomMap tags; - transaction.GetMainDicomTags(tags, *it); - - const DicomValue* value = tags.TestAndGetValue(DICOM_TAG_MODALITY); - - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - values.insert(value->GetContent()); - } - } - } - - std::string modalities; - Toolbox::JoinStrings(modalities, values, "\\"); - result.SetValue(DICOM_TAG_MODALITIES_IN_STUDY, modalities, false); - } - - if (requestedTags.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) > 0 - || requestedTags.count(DICOM_TAG_SOP_CLASSES_IN_STUDY) > 0) - { - for (std::list<int64_t>::const_iterator - it = seriesInternalIds.begin(); it != seriesInternalIds.end(); ++it) - { - std::list<int64_t> seriesInstancesIds; - transaction.GetChildrenInternalId(seriesInstancesIds, *it); - - instancesInternalIds.splice(instancesInternalIds.end(), seriesInstancesIds); - } - - if (requestedTags.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) > 0) - { - result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES, - boost::lexical_cast<std::string>(instancesInternalIds.size()), false); - } - - if (requestedTags.count(DICOM_TAG_SOP_CLASSES_IN_STUDY) > 0) - { - std::set<std::string> values; - - for (std::list<int64_t>::const_iterator - it = instancesInternalIds.begin(); it != instancesInternalIds.end(); ++it) - { - std::map<MetadataType, std::string> instanceMetadata; - // Extract the metadata - transaction.GetAllMetadata(instanceMetadata, *it); - - std::string value; - if (!LookupStringMetadata(value, instanceMetadata, MetadataType_Instance_SopClassUid)) - { - 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"); - } - - values.insert(value); - } - - std::string sopClassUids; - Toolbox::JoinStrings(sopClassUids, values, "\\"); - result.SetValue(DICOM_TAG_SOP_CLASSES_IN_STUDY, sopClassUids, false); - } - } - } - - static void ComputePatientTags(DicomMap& result, - ReadOnlyTransaction& transaction, - const std::string& patientPublicId, - int64_t patientInternalId, - const std::set<DicomTag>& requestedTags) - { - std::list<int64_t> studiesInternalIds; - std::list<int64_t> seriesInternalIds; - std::list<int64_t> instancesInternalIds; - - bool hasNbRelatedStudies = requestedTags.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES) > 0; - bool hasNbRelatedSeries = requestedTags.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES) > 0; - bool hasNbRelatedInstances = requestedTags.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES) > 0; - - transaction.GetChildrenInternalId(studiesInternalIds, patientInternalId); - - if (hasNbRelatedStudies) - { - result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES, - boost::lexical_cast<std::string>(studiesInternalIds.size()), false); - } - - if (hasNbRelatedSeries || hasNbRelatedInstances) - { - for (std::list<int64_t>::const_iterator - it = studiesInternalIds.begin(); it != studiesInternalIds.end(); ++it) - { - std::list<int64_t> thisSeriesIds; - transaction.GetChildrenInternalId(thisSeriesIds, *it); - seriesInternalIds.splice(seriesInternalIds.end(), thisSeriesIds); - - if (hasNbRelatedInstances) - { - for (std::list<int64_t>::const_iterator - it2 = seriesInternalIds.begin(); it2 != seriesInternalIds.end(); ++it2) - { - std::list<int64_t> thisInstancesIds; - transaction.GetChildrenInternalId(thisInstancesIds, *it2); - instancesInternalIds.splice(instancesInternalIds.end(), thisInstancesIds); - } - } - } - - if (hasNbRelatedSeries) - { - result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES, - boost::lexical_cast<std::string>(seriesInternalIds.size()), false); - } - - if (hasNbRelatedInstances) - { - result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES, - boost::lexical_cast<std::string>(instancesInternalIds.size()), false); - } - } - } public: virtual void ApplyTuple(ReadOnlyTransaction& transaction, @@ -933,6 +777,7 @@ else { ExpandedResource& target = tuple.get<1>(); + ExpandResourceDbFlags expandFlags = tuple.get<5>(); // Set information about the parent resource (if it exists) if (type == ResourceType_Patient) @@ -952,156 +797,134 @@ target.parentId_ = parent; } - // List the children resources - transaction.GetChildrenPublicId(target.childrenIds_, internalId); - - // Extract the metadata - transaction.GetAllMetadata(target.metadata_, internalId); - - // Set the resource type target.type_ = type; - - switch (type) + target.id_ = tuple.get<2>(); + + if (expandFlags & ExpandResourceDbFlags_IncludeChildren) { - case ResourceType_Patient: - case ResourceType_Study: - break; - - case ResourceType_Series: + // List the children resources + transaction.GetChildrenPublicId(target.childrenIds_, internalId); + } + + if (expandFlags & ExpandResourceDbFlags_IncludeMetadata) + { + // Extract the metadata + transaction.GetAllMetadata(target.metadata_, internalId); + + switch (type) { - int64_t i; - if (LookupIntegerMetadata(i, target.metadata_, MetadataType_Series_ExpectedNumberOfInstances)) - { - target.expectedNumberOfInstances_ = static_cast<int>(i); - target.status_ = EnumerationToString(transaction.GetSeriesStatus(internalId, i)); - } - else - { - target.expectedNumberOfInstances_ = -1; - target.status_ = EnumerationToString(SeriesStatus_Unknown); - } - - break; - } - - case ResourceType_Instance: - { - FileInfo attachment; - int64_t revision; // ignored - if (!transaction.LookupAttachment(attachment, revision, internalId, FileContentType_Dicom)) - { - throw OrthancException(ErrorCode_InternalError); - } - - target.fileSize_ = static_cast<unsigned int>(attachment.GetUncompressedSize()); - target.fileUuid_ = attachment.GetUuid(); - - int64_t i; - if (LookupIntegerMetadata(i, target.metadata_, MetadataType_Instance_IndexInSeries)) + case ResourceType_Patient: + case ResourceType_Study: + break; + + case ResourceType_Series: { - target.indexInSeries_ = static_cast<int>(i); - } - else - { - target.indexInSeries_ = -1; + int64_t i; + if (LookupIntegerMetadata(i, target.metadata_, MetadataType_Series_ExpectedNumberOfInstances)) + { + target.expectedNumberOfInstances_ = static_cast<int>(i); + target.status_ = EnumerationToString(transaction.GetSeriesStatus(internalId, i)); + } + else + { + target.expectedNumberOfInstances_ = -1; + target.status_ = EnumerationToString(SeriesStatus_Unknown); + } + + break; } - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - - // check the main dicom tags list has not changed since the resource was stored - target.mainDicomTagsSignature_ = DicomMap::GetDefaultMainDicomTagsSignature(type); - LookupStringMetadata(target.mainDicomTagsSignature_, target.metadata_, MetadataType_MainDicomTagsSignature); - - // Record the remaining information - target.id_ = tuple.get<2>(); - - // read all tags from DB - transaction.GetMainDicomTags(target.tags_, internalId); - - // check if we have access to all requestedTags or if we must get tags from parents - const std::set<DicomTag>& requestedTags = tuple.get<4>(); - - if (requestedTags.size() > 0) - { - std::set<DicomTag> savedMainDicomTags; - - FromDcmtkBridge::ParseListOfTags(savedMainDicomTags, target.mainDicomTagsSignature_); - - // read parent main dicom tags as long as we don't have gathered all requested tags - ResourceType currentLevel = target.type_; - int64_t currentInternalId = internalId; - Toolbox::GetMissingsFromSet(target.missingRequestedTags_, requestedTags, savedMainDicomTags); - - while ((target.missingRequestedTags_.size() > 0) - && currentLevel != ResourceType_Patient) - { - currentLevel = GetParentResourceType(currentLevel); - - int64_t currentParentId; - if (!transaction.LookupParent(currentParentId, currentInternalId)) + case ResourceType_Instance: { + FileInfo attachment; + int64_t revision; // ignored + if (!transaction.LookupAttachment(attachment, revision, internalId, FileContentType_Dicom)) + { + throw OrthancException(ErrorCode_InternalError); + } + + target.fileSize_ = static_cast<unsigned int>(attachment.GetUncompressedSize()); + target.fileUuid_ = attachment.GetUuid(); + + int64_t i; + if (LookupIntegerMetadata(i, target.metadata_, MetadataType_Instance_IndexInSeries)) + { + target.indexInSeries_ = static_cast<int>(i); + } + else + { + target.indexInSeries_ = -1; + } + break; } - std::map<MetadataType, std::string> parentMetadata; - transaction.GetAllMetadata(parentMetadata, currentParentId); - - std::string parentMainDicomTagsSignature = DicomMap::GetDefaultMainDicomTagsSignature(currentLevel); - LookupStringMetadata(parentMainDicomTagsSignature, parentMetadata, MetadataType_MainDicomTagsSignature); - - std::set<DicomTag> parentSavedMainDicomTags; - FromDcmtkBridge::ParseListOfTags(parentSavedMainDicomTags, parentMainDicomTagsSignature); - - size_t previousMissingCount = target.missingRequestedTags_.size(); - Toolbox::AppendSets(savedMainDicomTags, parentSavedMainDicomTags); - Toolbox::GetMissingsFromSet(target.missingRequestedTags_, requestedTags, savedMainDicomTags); - - // read the parent tags from DB only if it reduces the number of missing tags - if (target.missingRequestedTags_.size() < previousMissingCount) - { - Toolbox::AppendSets(savedMainDicomTags, parentSavedMainDicomTags); - - DicomMap parentTags; - transaction.GetMainDicomTags(parentTags, currentParentId); - - target.tags_.Merge(parentTags); - } - - currentInternalId = currentParentId; + default: + throw OrthancException(ErrorCode_InternalError); } - { // handle the tags that must be rebuilt because they are not saved in DB - if (target.type_ == ResourceType_Study && ( - target.missingRequestedTags_.count(DICOM_TAG_MODALITIES_IN_STUDY) > 0 - || target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) > 0 - || target.missingRequestedTags_.count(DICOM_TAG_SOP_CLASSES_IN_STUDY) > 0 - || target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES) > 0 - )) - { - ComputeStudyTags(target.tags_, transaction, target.id_, internalId, requestedTags); - } - - if (target.type_ == ResourceType_Series - && target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES) > 0) + // check the main dicom tags list has not changed since the resource was stored + target.mainDicomTagsSignature_ = DicomMap::GetDefaultMainDicomTagsSignature(type); + LookupStringMetadata(target.mainDicomTagsSignature_, target.metadata_, MetadataType_MainDicomTagsSignature); + } + + if (expandFlags & ExpandResourceDbFlags_IncludeMainDicomTags) + { + // read all tags from DB + transaction.GetMainDicomTags(target.tags_, internalId); + + // check if we have access to all requestedTags or if we must get tags from parents + const std::set<DicomTag>& requestedTags = tuple.get<4>(); + + if (requestedTags.size() > 0) + { + std::set<DicomTag> savedMainDicomTags; + + FromDcmtkBridge::ParseListOfTags(savedMainDicomTags, target.mainDicomTagsSignature_); + + // read parent main dicom tags as long as we don't have gathered all requested tags + ResourceType currentLevel = target.type_; + int64_t currentInternalId = internalId; + Toolbox::GetMissingsFromSet(target.missingRequestedTags_, requestedTags, savedMainDicomTags); + + while ((target.missingRequestedTags_.size() > 0) + && currentLevel != ResourceType_Patient) { - ComputeSeriesTags(target.tags_, target.childrenIds_, requestedTags); + currentLevel = GetParentResourceType(currentLevel); + + int64_t currentParentId; + if (!transaction.LookupParent(currentParentId, currentInternalId)) + { + break; + } + + std::map<MetadataType, std::string> parentMetadata; + transaction.GetAllMetadata(parentMetadata, currentParentId); + + std::string parentMainDicomTagsSignature = DicomMap::GetDefaultMainDicomTagsSignature(currentLevel); + LookupStringMetadata(parentMainDicomTagsSignature, parentMetadata, MetadataType_MainDicomTagsSignature); + + std::set<DicomTag> parentSavedMainDicomTags; + FromDcmtkBridge::ParseListOfTags(parentSavedMainDicomTags, parentMainDicomTagsSignature); + + size_t previousMissingCount = target.missingRequestedTags_.size(); + Toolbox::AppendSets(savedMainDicomTags, parentSavedMainDicomTags); + Toolbox::GetMissingsFromSet(target.missingRequestedTags_, requestedTags, savedMainDicomTags); + + // read the parent tags from DB only if it reduces the number of missing tags + if (target.missingRequestedTags_.size() < previousMissingCount) + { + Toolbox::AppendSets(savedMainDicomTags, parentSavedMainDicomTags); + + DicomMap parentTags; + transaction.GetMainDicomTags(parentTags, currentParentId); + + target.tags_.Merge(parentTags); + } + + currentInternalId = currentParentId; } - - if (target.type_ == ResourceType_Patient && ( - target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES) > 0 - || target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES) > 0 - || target.missingRequestedTags_.count(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES) > 0 - )) - { - ComputePatientTags(target.tags_, transaction, target.id_, internalId, requestedTags); - } - } - + } } std::string tmp; @@ -1139,7 +962,7 @@ bool found; Operations operations; - operations.Apply(*this, found, target, publicId, level, requestedTags); + operations.Apply(*this, found, target, publicId, level, requestedTags, expandFlags); return found; }