diff OrthancServer/Sources/Database/Compatibility/GenericFind.cpp @ 5596:81a29ad7fb4b find-refactoring

added possibility to retrieve main DICOM tags and metadata at any level
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 07 May 2024 18:44:53 +0200
parents a87f2a56257d
children 6e2dad336446
line wrap: on
line diff
--- a/OrthancServer/Sources/Database/Compatibility/GenericFind.cpp	Tue May 07 12:53:12 2024 +0200
+++ b/OrthancServer/Sources/Database/Compatibility/GenericFind.cpp	Tue May 07 18:44:53 2024 +0200
@@ -25,6 +25,8 @@
 #include "../../../../OrthancFramework/Sources/DicomFormat/DicomArray.h"
 #include "../../../../OrthancFramework/Sources/OrthancException.h"
 
+#include <stack>
+
 
 namespace Orthanc
 {
@@ -59,6 +61,91 @@
     }
 
 
+    void GenericFind::RetrieveMainDicomTags(FindResponse::Resource& target,
+                                            ResourceType level,
+                                            int64_t internalId)
+    {
+      DicomMap m;
+      transaction_.GetMainDicomTags(m, internalId);
+
+      DicomArray a(m);
+      for (size_t i = 0; i < a.GetSize(); i++)
+      {
+        const DicomElement& element = a.GetElement(i);
+        if (element.GetValue().IsString())
+        {
+          target.AddStringDicomTag(level, element.GetTag().GetGroup(),
+                                   element.GetTag().GetElement(), element.GetValue().GetContent());
+        }
+        else
+        {
+          throw OrthancException(ErrorCode_BadParameterType);
+        }
+      }
+    }
+
+
+    static ResourceType GetTopLevelOfInterest(const FindRequest& request)
+    {
+      switch (request.GetLevel())
+      {
+        case ResourceType_Patient:
+          return ResourceType_Patient;
+
+        case ResourceType_Study:
+          if (request.IsRetrieveMainDicomTags(ResourceType_Patient) ||
+              request.IsRetrieveMetadata(ResourceType_Patient))
+          {
+            return ResourceType_Patient;
+          }
+          else
+          {
+            return ResourceType_Study;
+          }
+
+        case ResourceType_Series:
+          if (request.IsRetrieveMainDicomTags(ResourceType_Patient) ||
+              request.IsRetrieveMetadata(ResourceType_Patient))
+          {
+            return ResourceType_Patient;
+          }
+          else if (request.IsRetrieveMainDicomTags(ResourceType_Study) ||
+                   request.IsRetrieveMetadata(ResourceType_Study))
+          {
+            return ResourceType_Study;
+          }
+          else
+          {
+            return ResourceType_Series;
+          }
+
+        case ResourceType_Instance:
+          if (request.IsRetrieveMainDicomTags(ResourceType_Patient) ||
+              request.IsRetrieveMetadata(ResourceType_Patient))
+          {
+            return ResourceType_Patient;
+          }
+          else if (request.IsRetrieveMainDicomTags(ResourceType_Study) ||
+                   request.IsRetrieveMetadata(ResourceType_Study))
+          {
+            return ResourceType_Study;
+          }
+          else if (request.IsRetrieveMainDicomTags(ResourceType_Series) ||
+                   request.IsRetrieveMetadata(ResourceType_Series))
+          {
+            return ResourceType_Series;
+          }
+          else
+          {
+            return ResourceType_Instance;
+          }
+
+        default:
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+    }
+
+
     void GenericFind::ExecuteExpand(FindResponse& response,
                                     const FindRequest& request,
                                     const std::string& identifier)
@@ -110,32 +197,43 @@
         resource->SetParentIdentifier(parent);
       }
 
-      if (request.IsRetrieveMainDicomTags())
       {
-        DicomMap m;
-        transaction_.GetMainDicomTags(m, internalId);
+        int64_t currentId = internalId;
+        ResourceType currentLevel = level;
+        const ResourceType topLevel = GetTopLevelOfInterest(request);
 
-        DicomArray a(m);
-        for (size_t i = 0; i < a.GetSize(); i++)
+        for (;;)
         {
-          const DicomElement& element = a.GetElement(i);
-          if (element.GetValue().IsString())
+          if (request.IsRetrieveMainDicomTags(currentLevel))
+          {
+            RetrieveMainDicomTags(*resource, currentLevel, currentId);
+          }
+
+          if (request.IsRetrieveMetadata(currentLevel))
           {
-            resource->AddStringDicomTag(element.GetTag().GetGroup(), element.GetTag().GetElement(),
-                                        element.GetValue().GetContent());
+            transaction_.GetAllMetadata(resource->GetMetadata(currentLevel), currentId);
+          }
+
+          if (currentLevel == topLevel)
+          {
+            break;
           }
           else
           {
-            throw OrthancException(ErrorCode_BadParameterType);
+            int64_t parentId;
+            if (transaction_.LookupParent(parentId, currentId))
+            {
+              currentId = parentId;
+              currentLevel = GetParentResourceType(currentLevel);
+            }
+            else
+            {
+              throw OrthancException(ErrorCode_DatabasePlugin);
+            }
           }
         }
       }
 
-      if (request.IsRetrieveMetadata())
-      {
-        transaction_.GetAllMetadata(resource->GetMetadata(), internalId);
-      }
-
       if (request.IsRetrieveLabels())
       {
         transaction_.ListLabels(resource->GetLabels(), internalId);
@@ -169,7 +267,7 @@
 
         for (std::list<std::string>::const_iterator it = children.begin(); it != children.end(); ++it)
         {
-          resource->AddChildIdentifier(GetChildResourceType(level), *it);
+          resource->AddChildIdentifier(*it);
         }
       }
 
@@ -181,6 +279,50 @@
         resource->AddChildrenMetadata(*it, values);
       }
 
+      if (!request.GetRetrieveAttachmentOfOneInstance().empty())
+      {
+        std::set<FileContentType> todo = request.GetRetrieveAttachmentOfOneInstance();
+        std::stack< std::pair<ResourceType, int64_t> > candidates;
+        candidates.push(std::make_pair(level, internalId));
+
+        while (!todo.empty() &&
+               !candidates.empty())
+        {
+          std::pair<ResourceType, int64_t> top = candidates.top();
+          candidates.pop();
+
+          if (top.first == ResourceType_Instance)
+          {
+            std::set<FileContentType> nextTodo;
+
+            for (std::set<FileContentType>::const_iterator it = todo.begin(); it != todo.end(); ++it)
+            {
+              FileInfo attachment;
+              int64_t revision;
+              if (transaction_.LookupAttachment(attachment, revision, top.second, *it))
+              {
+                resource->AddAttachmentOfOneInstance(attachment);
+              }
+              else
+              {
+                nextTodo.insert(*it);
+              }
+            }
+
+            todo = nextTodo;
+          }
+          else
+          {
+            std::list<int64_t> children;
+            transaction_.GetChildrenInternalId(children, top.second);
+            for (std::list<int64_t>::const_iterator it = children.begin(); it != children.end(); ++it)
+            {
+              candidates.push(std::make_pair(GetChildResourceType(top.first), *it));
+            }
+          }
+        }
+      }
+
       response.Add(resource.release());
     }
   }