# HG changeset patch # User Sebastien Jodogne # Date 1715079192 -7200 # Node ID a87f2a56257d76582b97c29849679dbae6b0c66b # Parent a906dc19264c315be987da23b7d16dd2c99f0f9d implemented FindRequest::retrieveChildrenMetadata_ diff -r a906dc19264c -r a87f2a56257d OrthancServer/Sources/Database/Compatibility/GenericFind.cpp --- a/OrthancServer/Sources/Database/Compatibility/GenericFind.cpp Sat May 04 15:25:19 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/GenericFind.cpp Tue May 07 12:53:12 2024 +0200 @@ -65,14 +65,51 @@ { int64_t internalId; ResourceType level; - if (!transaction_.LookupResource(internalId, level, identifier) || - level != request.GetLevel()) + std::string parent; + + if (request.IsRetrieveParentIdentifier()) { - throw OrthancException(ErrorCode_InternalError); + if (!transaction_.LookupResourceAndParent(internalId, level, parent, identifier)) + { + return; // The resource is not available anymore + } + + if (level == ResourceType_Patient) + { + if (!parent.empty()) + { + throw OrthancException(ErrorCode_DatabasePlugin); + } + } + else + { + if (parent.empty()) + { + throw OrthancException(ErrorCode_DatabasePlugin); + } + } + } + else + { + if (!transaction_.LookupResource(internalId, level, identifier)) + { + return; // The resource is not available anymore + } + } + + if (level != request.GetLevel()) + { + throw OrthancException(ErrorCode_DatabasePlugin); } std::unique_ptr resource(new FindResponse::Resource(request.GetLevel(), identifier)); + if (request.IsRetrieveParentIdentifier()) + { + assert(!parent.empty()); + resource->SetParentIdentifier(parent); + } + if (request.IsRetrieveMainDicomTags()) { DicomMap m; @@ -120,24 +157,11 @@ } else { - throw OrthancException(ErrorCode_InternalError); + throw OrthancException(ErrorCode_DatabasePlugin); } } } - if (request.IsRetrieveParentIdentifier()) - { - int64_t parentId; - if (transaction_.LookupParent(parentId, internalId)) - { - resource->SetParentIdentifier(transaction_.GetPublicId(parentId)); - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - } - if (request.IsRetrieveChildrenIdentifiers()) { std::list children; @@ -149,10 +173,12 @@ } } - if (request.IsRetrieveChildrenMetadata()) + for (std::set::const_iterator it = request.GetRetrieveChildrenMetadata().begin(); + it != request.GetRetrieveChildrenMetadata().end(); ++it) { - // TODO-FIND - throw OrthancException(ErrorCode_NotImplemented); + std::list values; + transaction_.GetChildrenMetadata(values, internalId, *it); + resource->AddChildrenMetadata(*it, values); } response.Add(resource.release()); diff -r a906dc19264c -r a87f2a56257d OrthancServer/Sources/Database/FindRequest.cpp --- a/OrthancServer/Sources/Database/FindRequest.cpp Sat May 04 15:25:19 2024 +0200 +++ b/OrthancServer/Sources/Database/FindRequest.cpp Tue May 07 12:53:12 2024 +0200 @@ -39,8 +39,7 @@ retrieveLabels_(false), retrieveAttachments_(false), retrieveParentIdentifier_(false), - retrieveChildrenIdentifiers_(false), - retrieveChildrenMetadata_(false) + retrieveChildrenIdentifiers_(false) { } @@ -155,15 +154,15 @@ } - void FindRequest::SetRetrieveChildrenMetadata(bool retrieve) + void FindRequest::AddRetrieveChildrenMetadata(MetadataType metadata) { - if (level_ == ResourceType_Instance) + if (IsRetrieveChildrenMetadata(metadata)) { throw OrthancException(ErrorCode_BadParameterType); } else { - retrieveChildrenMetadata_ = retrieve; + retrieveChildrenMetadata_.insert(metadata); } } } diff -r a906dc19264c -r a87f2a56257d OrthancServer/Sources/Database/FindRequest.h --- a/OrthancServer/Sources/Database/FindRequest.h Sat May 04 15:25:19 2024 +0200 +++ b/OrthancServer/Sources/Database/FindRequest.h Tue May 07 12:53:12 2024 +0200 @@ -74,9 +74,9 @@ class Key { private: - KeyType type_; - boost::shared_ptr dicomTag_; - MetadataType metadata_; + KeyType type_; + DicomTag dicomTag_; + MetadataType metadata_; // TODO-FIND: to execute the query, we actually need: // ResourceType level_; @@ -86,13 +86,14 @@ public: explicit Key(const DicomTag& dicomTag) : type_(KeyType_DicomTag), - dicomTag_(new DicomTag(dicomTag)), + dicomTag_(dicomTag), metadata_(MetadataType_EndUser) { } explicit Key(MetadataType metadata) : type_(KeyType_Metadata), + dicomTag_(0, 0), metadata_(metadata) { } @@ -105,7 +106,7 @@ const DicomTag& GetDicomTag() const { assert(GetType() == KeyType_DicomTag); - return *dicomTag_; + return dicomTag_; } MetadataType GetMetadataType() const @@ -171,7 +172,7 @@ bool retrieveAttachments_; bool retrieveParentIdentifier_; bool retrieveChildrenIdentifiers_; - bool retrieveChildrenMetadata_; + std::set retrieveChildrenMetadata_; public: explicit FindRequest(ResourceType level); @@ -312,9 +313,14 @@ return retrieveChildrenIdentifiers_; } - void SetRetrieveChildrenMetadata(bool retrieve); + void AddRetrieveChildrenMetadata(MetadataType metadata); - bool IsRetrieveChildrenMetadata() const + bool IsRetrieveChildrenMetadata(MetadataType metadata) const + { + return retrieveChildrenMetadata_.find(metadata) != retrieveChildrenMetadata_.end(); + } + + const std::set& GetRetrieveChildrenMetadata() const { return retrieveChildrenMetadata_; } diff -r a906dc19264c -r a87f2a56257d OrthancServer/Sources/Database/FindResponse.cpp --- a/OrthancServer/Sources/Database/FindResponse.cpp Sat May 04 15:25:19 2024 +0200 +++ b/OrthancServer/Sources/Database/FindResponse.cpp Tue May 07 12:53:12 2024 +0200 @@ -24,6 +24,7 @@ #include "../../../OrthancFramework/Sources/DicomFormat/DicomInstanceHasher.h" #include "../../../OrthancFramework/Sources/OrthancException.h" +#include "../../../OrthancFramework/Sources/SerializationToolbox.h" #include @@ -250,6 +251,12 @@ assert(it->second != NULL); delete it->second; } + + for (ChildrenMetadata::iterator it = childrenMetadata_.begin(); it != childrenMetadata_.end(); ++it) + { + assert(it->second != NULL); + delete it->second; + } } @@ -324,7 +331,97 @@ } - void FindResponse::Resource::Format(Json::Value& target, + void FindResponse::Resource::AddChildrenMetadata(MetadataType metadata, + const std::list& values) + { + if (childrenMetadata_.find(metadata) == childrenMetadata_.end()) + { + childrenMetadata_[metadata] = new std::list(values); + } + else + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + } + + + bool FindResponse::Resource::LookupChildrenMetadata(std::list& values, + MetadataType metadata) const + { + ChildrenMetadata::const_iterator found = childrenMetadata_.find(metadata); + if (found == childrenMetadata_.end()) + { + return false; + } + else + { + assert(found->second != NULL); + values = *found->second; + return true; + } + } + + + SeriesStatus FindResponse::Resource::GetSeriesStatus(uint32_t& expectedNumberOfInstances) const + { + if (level_ != ResourceType_Series) + { + throw OrthancException(ErrorCode_BadParameterType); + } + + std::string s; + if (!LookupMetadata(s, MetadataType_Series_ExpectedNumberOfInstances) || + !SerializationToolbox::ParseUnsignedInteger32(expectedNumberOfInstances, s)) + { + return SeriesStatus_Unknown; + } + + std::list values; + if (!LookupChildrenMetadata(values, MetadataType_Instance_IndexInSeries)) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + + std::set instances; + + for (std::list::const_iterator + it = values.begin(); it != values.end(); ++it) + { + int64_t index; + + if (!SerializationToolbox::ParseInteger64(index, *it)) + { + return SeriesStatus_Unknown; + } + + if (index <= 0 || + index > static_cast(expectedNumberOfInstances)) + { + // Out-of-range instance index + return SeriesStatus_Inconsistent; + } + + if (instances.find(index) != instances.end()) + { + // Twice the same instance index + return SeriesStatus_Inconsistent; + } + + instances.insert(index); + } + + if (instances.size() == static_cast(expectedNumberOfInstances)) + { + return SeriesStatus_Complete; + } + else + { + return SeriesStatus_Missing; + } + } + + + void FindResponse::Resource::Expand(Json::Value& target, const FindRequest& request) const { /** diff -r a906dc19264c -r a87f2a56257d OrthancServer/Sources/Database/FindResponse.h --- a/OrthancServer/Sources/Database/FindResponse.h Sat May 04 15:25:19 2024 +0200 +++ b/OrthancServer/Sources/Database/FindResponse.h Tue May 07 12:53:12 2024 +0200 @@ -62,7 +62,8 @@ private: class DicomValue; - typedef std::map MainDicomTags; + typedef std::map MainDicomTags; + typedef std::map*> ChildrenMetadata; ResourceType level_; std::string identifier_; @@ -74,6 +75,7 @@ std::set labels_; std::map metadata_; std::map attachments_; + ChildrenMetadata childrenMetadata_; ChildrenAtLevel& GetChildrenAtLevel(ResourceType level); @@ -170,7 +172,15 @@ bool LookupAttachment(FileInfo& target, FileContentType type) const; - void Format(Json::Value& target, + void AddChildrenMetadata(MetadataType metadata, + const std::list& values); + + bool LookupChildrenMetadata(std::list& values, + MetadataType metadata) const; + + SeriesStatus GetSeriesStatus(uint32_t& expecterNumberOfInstances) const; + + void Expand(Json::Value& target, const FindRequest& request) const; }; diff -r a906dc19264c -r a87f2a56257d OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp --- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Sat May 04 15:25:19 2024 +0200 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Tue May 07 12:53:12 2024 +0200 @@ -937,7 +937,7 @@ Toolbox::GetMissingsFromSet(target.missingRequestedTags_, requestedTags, savedMainDicomTags); while ((target.missingRequestedTags_.size() > 0) - && currentLevel != ResourceType_Patient) + && currentLevel != ResourceType_Patient) { currentLevel = GetParentResourceType(currentLevel); @@ -2548,7 +2548,7 @@ catch (boost::bad_lexical_cast&) { LOG(ERROR) << "Cannot read the global sequence " - << boost::lexical_cast(sequence_) << ", resetting it"; + << boost::lexical_cast(sequence_) << ", resetting it"; oldValue = 0; } @@ -2847,8 +2847,8 @@ public: explicit Operations(const ParsedDicomFile& dicom, bool limitToThisLevelDicomTags, ResourceType limitToLevel) - : limitToThisLevelDicomTags_(limitToThisLevelDicomTags), - limitToLevel_(limitToLevel) + : limitToThisLevelDicomTags_(limitToThisLevelDicomTags), + limitToLevel_(limitToLevel) { OrthancConfiguration::DefaultExtractDicomSummary(summary_, dicom); hasher_.reset(new DicomInstanceHasher(summary_)); @@ -2973,7 +2973,7 @@ } bool StatelessDatabaseOperations::ReadWriteTransaction::HasReachedMaxPatientCount(unsigned int maximumPatientCount, - const std::string& patientId) + const std::string& patientId) { if (maximumPatientCount != 0) { @@ -3075,7 +3075,7 @@ }; if (maximumStorageMode == MaxStorageMode_Recycle - && (maximumStorageSize != 0 || maximumPatientCount != 0)) + && (maximumStorageSize != 0 || maximumPatientCount != 0)) { Operations operations(maximumStorageSize, maximumPatientCount); Apply(operations); @@ -3139,9 +3139,9 @@ } static void SetMainDicomSequenceMetadata(ResourcesContent& content, - int64_t resource, - const DicomMap& dicomSummary, - ResourceType level) + int64_t resource, + const DicomMap& dicomSummary, + ResourceType level) { std::string serialized; GetMainDicomSequenceMetadataContent(serialized, dicomSummary, level); @@ -3334,7 +3334,7 @@ // Ensure there is enough room in the storage for the new instance uint64_t instanceSize = 0; for (Attachments::const_iterator it = attachments_.begin(); - it != attachments_.end(); ++it) + it != attachments_.end(); ++it) { instanceSize += it->GetCompressedSize(); } @@ -3363,7 +3363,7 @@ // Attach the files to the newly created instance for (Attachments::const_iterator it = attachments_.begin(); - it != attachments_.end(); ++it) + it != attachments_.end(); ++it) { if (isReconstruct_) { @@ -3380,7 +3380,7 @@ // Attach the user-specified metadata (in case of reconstruction, metadata_ contains all past metadata, including the system ones we want to keep) for (MetadataMap::const_iterator - it = metadata_.begin(); it != metadata_.end(); ++it) + it = metadata_.begin(); it != metadata_.end(); ++it) { switch (it->first.first) { @@ -3998,7 +3998,7 @@ } } - if (request.IsRetrieveChildrenMetadata()) + //if (request.IsRetrieveChildrenMetadata()) { // TODO-FIND: the status_ is normally obtained from transaction.GetSeriesStatus(internalId, i) // but, that's an heavy operation for something that is rarely used -> we should have dedicated SQL code diff -r a906dc19264c -r a87f2a56257d OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp --- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Sat May 04 15:25:19 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Tue May 07 12:53:12 2024 +0200 @@ -251,7 +251,7 @@ if (resourceType == ResourceType_Series) { - request.SetRetrieveChildrenMetadata(true); // required for the SeriesStatus + request.AddRetrieveChildrenMetadata(MetadataType_Instance_IndexInSeries); // required for the SeriesStatus } if (resourceType == ResourceType_Instance)