changeset 5595:a87f2a56257d find-refactoring

implemented FindRequest::retrieveChildrenMetadata_
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 07 May 2024 12:53:12 +0200
parents a906dc19264c
children 81a29ad7fb4b
files OrthancServer/Sources/Database/Compatibility/GenericFind.cpp OrthancServer/Sources/Database/FindRequest.cpp OrthancServer/Sources/Database/FindRequest.h OrthancServer/Sources/Database/FindResponse.cpp OrthancServer/Sources/Database/FindResponse.h OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp
diffstat 7 files changed, 188 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- 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<FindResponse::Resource> 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<std::string> children;
@@ -149,10 +173,12 @@
         }
       }
 
-      if (request.IsRetrieveChildrenMetadata())
+      for (std::set<MetadataType>::const_iterator it = request.GetRetrieveChildrenMetadata().begin();
+           it != request.GetRetrieveChildrenMetadata().end(); ++it)
       {
-        // TODO-FIND
-        throw OrthancException(ErrorCode_NotImplemented);
+        std::list<std::string> values;
+        transaction_.GetChildrenMetadata(values, internalId, *it);
+        resource->AddChildrenMetadata(*it, values);
       }
 
       response.Add(resource.release());
--- 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);
     }
   }
 }
--- 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>   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<MetadataType>               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<MetadataType>& GetRetrieveChildrenMetadata() const
     {
       return retrieveChildrenMetadata_;
     }
--- 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 <cassert>
 
@@ -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<std::string>& values)
+  {
+    if (childrenMetadata_.find(metadata) == childrenMetadata_.end())
+    {
+      childrenMetadata_[metadata] = new std::list<std::string>(values);
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+  }
+
+
+  bool FindResponse::Resource::LookupChildrenMetadata(std::list<std::string>& 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<std::string> values;
+    if (!LookupChildrenMetadata(values, MetadataType_Instance_IndexInSeries))
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
+    std::set<int64_t> instances;
+
+    for (std::list<std::string>::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<int64_t>(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<size_t>(expectedNumberOfInstances))
+    {
+      return SeriesStatus_Complete;
+    }
+    else
+    {
+      return SeriesStatus_Missing;
+    }
+  }
+
+
+  void FindResponse::Resource::Expand(Json::Value& target,
                                       const FindRequest& request) const
   {
     /**
--- 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<DicomTag, DicomValue*>  MainDicomTags;
+      typedef std::map<DicomTag, DicomValue*>                  MainDicomTags;
+      typedef std::map<MetadataType, std::list<std::string>*>  ChildrenMetadata;
 
       ResourceType                          level_;
       std::string                           identifier_;
@@ -74,6 +75,7 @@
       std::set<std::string>                 labels_;      
       std::map<MetadataType, std::string>   metadata_;
       std::map<FileContentType, FileInfo>   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<std::string>& values);
+
+      bool LookupChildrenMetadata(std::list<std::string>& values,
+                                  MetadataType metadata) const;
+
+      SeriesStatus GetSeriesStatus(uint32_t& expecterNumberOfInstances) const;
+
+      void Expand(Json::Value& target,
                   const FindRequest& request) const;
     };
 
--- 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<std::string>(sequence_) << ", resetting it";
+                         << boost::lexical_cast<std::string>(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 
--- 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)