changeset 5590:8b32213af23e find-refactoring

replaced FindRequest::ResponseContent by booleans
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 03 May 2024 18:17:53 +0200
parents b51ee994cd6f
children 043c8016ed6a
files OrthancServer/Sources/Database/Compatibility/GenericFind.cpp OrthancServer/Sources/Database/FindRequest.cpp OrthancServer/Sources/Database/FindRequest.h OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp OrthancServer/Sources/ServerContext.cpp
diffstat 7 files changed, 263 insertions(+), 224 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/Sources/Database/Compatibility/GenericFind.cpp	Fri May 03 17:26:06 2024 +0200
+++ b/OrthancServer/Sources/Database/Compatibility/GenericFind.cpp	Fri May 03 18:17:53 2024 +0200
@@ -32,8 +32,7 @@
     void GenericFind::Execute(FindResponse& response,
                               const FindRequest& request)
     {
-      if (request.GetResponseContent() == FindRequest::ResponseContent_IdentifiersOnly &&
-          !request.GetOrthancIdentifiers().HasPatientId() &&
+      if (!request.GetOrthancIdentifiers().HasPatientId() &&
           !request.GetOrthancIdentifiers().HasStudyId() &&
           !request.GetOrthancIdentifiers().HasSeriesId() &&
           !request.GetOrthancIdentifiers().HasInstanceId() &&
@@ -76,7 +75,7 @@
       {
         const FindResponse::Resource& resource = response.GetResource(i);
 
-        if (request.HasResponseContent(FindRequest::ResponseContent_MainDicomTags))
+        if (request.IsRetrieveTagsAtLevel(request.GetLevel()))
         {
           DicomMap tmp;
           resource.GetDicomTagsAtLevel(tmp, request.GetLevel());
--- a/OrthancServer/Sources/Database/FindRequest.cpp	Fri May 03 17:26:06 2024 +0200
+++ b/OrthancServer/Sources/Database/FindRequest.cpp	Fri May 03 18:17:53 2024 +0200
@@ -62,11 +62,16 @@
     hasLimits_(false),
     limitsSince_(0),
     limitsCount_(0),
-    responseContent_(ResponseContent_IdentifiersOnly),
     retrievePatientTags_(false),
     retrieveStudyTags_(false),
     retrieveSeriesTags_(false),
-    retrieveInstanceTags_(false)
+    retrieveInstanceTags_(false),
+    retrieveMetadata_(false),
+    retrieveLabels_(false),
+    retrieveAttachments_(false),
+    retrieveParentIdentifier_(false),
+    retrieveChildrenIdentifiers_(false),
+    retrieveChildrenMetadata_(false)
   {
   }
 
@@ -207,4 +212,42 @@
     ordering_.push_back(new Ordering(Key(metadataType), direction));
   }
 
+
+  void FindRequest::SetRetrieveParentIdentifier(bool retrieve)
+  {
+    if (level_ == ResourceType_Patient)
+    {
+      throw OrthancException(ErrorCode_BadParameterType);
+    }
+    else
+    {
+      retrieveParentIdentifier_ = retrieve;
+    }
+  }
+
+
+  void FindRequest::SetRetrieveChildrenIdentifiers(bool retrieve)
+  {
+    if (level_ == ResourceType_Instance)
+    {
+      throw OrthancException(ErrorCode_BadParameterType);
+    }
+    else
+    {
+      retrieveChildrenIdentifiers_ = retrieve;
+    }
+  }
+
+
+  void FindRequest::SetRetrieveChildrenMetadata(bool retrieve)
+  {
+    if (level_ == ResourceType_Instance)
+    {
+      throw OrthancException(ErrorCode_BadParameterType);
+    }
+    else
+    {
+      retrieveChildrenMetadata_ = retrieve;
+    }
+  }
 }
--- a/OrthancServer/Sources/Database/FindRequest.h	Fri May 03 17:26:06 2024 +0200
+++ b/OrthancServer/Sources/Database/FindRequest.h	Fri May 03 18:17:53 2024 +0200
@@ -40,30 +40,22 @@
   class FindRequest : public boost::noncopyable
   {
   public:
-    enum ResponseContent
-    {
-      ResponseContent_MainDicomTags         = (1 << 0),     // retrieve all tags from MainDicomTags and DicomIdentifiers
-      ResponseContent_Metadata              = (1 << 1),     // retrieve all metadata, their values and revision
-      ResponseContent_Labels                = (1 << 2),     // get all labels
-      ResponseContent_Attachments           = (1 << 3),     // retrieve all attachments, their values and revision
-      ResponseContent_Parent                = (1 << 4),     // get the id of the parent
-      ResponseContent_Children              = (1 << 5),     // retrieve the list of children ids
-      ResponseContent_ChildInstanceId       = (1 << 6),     // When you need to access all tags from a patient/study/series, you might need to open the DICOM file of a child instance
-      ResponseContent_ChildrenMetadata      = (1 << 7),     // That is actually required to compute the series status but could be usefull for other stuffs.
-      ResponseContent_IsStable              = (1 << 8),     // This is currently not saved in DB but it could be in the future.
+    /**
+
+       TO DISCUSS:
+
+       (1) ResponseContent_ChildInstanceId       = (1 << 6),     // When you need to access all tags from a patient/study/series, you might need to open the DICOM file of a child instance
 
-      ResponseContent_IdentifiersOnly       = 0,
-      ResponseContent_INTERNAL              = 0x7FFFFFFF
-    };
+       if (requestedTags.size() > 0 && resourceType != ResourceType_Instance) // if we are requesting specific tags that might be outside of the MainDicomTags, we must get a childInstanceId too
+       {
+       responseContent = static_cast<FindRequest::ResponseContent>(responseContent | FindRequest::ResponseContent_ChildInstanceId);
+       }
 
-    enum ConstraintType
-    {
-      ConstraintType_Mandatory,
-      ConstraintType_Equality,
-      ConstraintType_Range,
-      ConstraintType_Wildcard,
-      ConstraintType_List
-    };
+
+       (2) ResponseContent_IsStable              = (1 << 8),     // This is currently not saved in DB but it could be in the future.
+
+     **/
+
 
     enum KeyType  // used for ordering and filters
     {
@@ -71,6 +63,7 @@
       KeyType_Metadata
     };
 
+
     enum OrderingDirection
     {
       OrderingDirection_Ascending,
@@ -172,15 +165,18 @@
     LabelsConstraint                     labelsContraint_;
     std::deque<Ordering*>                ordering_;             // The ordering criteria (note: the order is important !)
 
-    // response fields
-    ResponseContent                      responseContent_;
-    
-    // TODO: check if these 4 options are required.  We might just have a retrieveParentTags that could be part of the ResponseContent enum ?
     bool                                 retrievePatientTags_;
     bool                                 retrieveStudyTags_;
     bool                                 retrieveSeriesTags_;
     bool                                 retrieveInstanceTags_;
 
+    bool                                 retrieveMetadata_;
+    bool                                 retrieveLabels_;
+    bool                                 retrieveAttachments_;
+    bool                                 retrieveParentIdentifier_;
+    bool                                 retrieveChildrenIdentifiers_;
+    bool                                 retrieveChildrenMetadata_;
+
     bool IsCompatibleLevel(ResourceType levelOfInterest) const;
 
   public:
@@ -193,32 +189,6 @@
       return level_;
     }
 
-
-    void SetResponseContent(ResponseContent content)
-    {
-      responseContent_ = content;
-    }
-
-    void AddResponseContent(ResponseContent content)
-    {
-      responseContent_ = static_cast<ResponseContent>(static_cast<uint32_t>(responseContent_) | content);
-    }
-
-    ResponseContent GetResponseContent() const
-    {
-      return responseContent_;
-    }
-
-    bool HasResponseContent(ResponseContent content) const
-    {
-      return (responseContent_ & content) == content;
-    }
-
-    bool IsResponseIdentifiersOnly() const
-    {
-      return responseContent_ == ResponseContent_IdentifiersOnly;
-    }
-
     void SetOrthancPatientId(const std::string& id)
     {
       orthancIdentifiers_.SetPatientId(id);
@@ -244,7 +214,6 @@
       return orthancIdentifiers_;
     }
 
-
     void AddDicomTagConstraint(const DicomTagConstraint& constraint);
 
     size_t GetDicomTagConstraintsCount() const
@@ -271,7 +240,6 @@
 
     uint64_t GetLimitsCount() const;
 
-
     void SetRetrieveTagsAtLevel(ResourceType levelOfInterest,
                                 bool retrieve);
 
@@ -300,5 +268,56 @@
     {
       return labelsContraint_;
     }
+
+    void SetRetrieveMetadata(bool retrieve)
+    {
+      retrieveMetadata_ = retrieve;
+    }
+
+    bool IsRetrieveMetadata() const
+    {
+      return retrieveMetadata_;
+    }
+
+    void SetRetrieveLabels(bool retrieve)
+    {
+      retrieveLabels_ = retrieve;
+    }
+
+    bool IsRetrieveLabels() const
+    {
+      return retrieveLabels_;
+    }
+
+    void SetRetrieveAttachments(bool retrieve)
+    {
+      retrieveAttachments_ = retrieve;
+    }
+
+    bool IsRetrieveAttachments() const
+    {
+      return retrieveAttachments_;
+    }
+
+    void SetRetrieveParentIdentifier(bool retrieve);
+
+    bool IsRetrieveParentIdentifier() const
+    {
+      return retrieveParentIdentifier_;
+    }
+
+    void SetRetrieveChildrenIdentifiers(bool retrieve);
+
+    bool IsRetrieveChildrenIdentifiers() const
+    {
+      return retrieveChildrenIdentifiers_;
+    }
+
+    void SetRetrieveChildrenMetadata(bool retrieve);
+
+    bool IsRetrieveChildrenMetadata() const
+    {
+      return retrieveChildrenMetadata_;
+    }
   };
 }
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Fri May 03 17:26:06 2024 +0200
+++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Fri May 03 18:17:53 2024 +0200
@@ -1166,151 +1166,138 @@
                                request.GetLabelsConstraint(),
                                (request.HasLimits() ? request.GetLimitsCount() : 0));  // TODO: handles since and count
 
-        if (request.IsResponseIdentifiersOnly())
+        {
+          // first create a temporary table that with the filtered and ordered results
+          sqlLookup = "CREATE TEMPORARY TABLE FilteredResourcesIds AS " + sqlLookup;
+
+          SQLite::Statement statement(db_, SQLITE_FROM_HERE_DYNAMIC(sqlLookup), sqlLookup);
+          formatter.Bind(statement);
+          statement.Run();
+        }
+
+        {
+          // create the response item with the public ids only
+          SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT publicId FROM FilteredResourcesIds");
+          formatter.Bind(statement);
+
+          while (statement.Step())
+          {
+            const std::string resourceId = statement.ColumnString(0);
+            response.Add(new FindResponse::Resource(request.GetLevel(), resourceId));
+          }
+        }
+
+        // request Each response content through INNER JOIN with the temporary table
+        if (request.IsRetrieveTagsAtLevel(request.GetLevel()))
         {
-          SQLite::Statement statement(db_, SQLITE_FROM_HERE_DYNAMIC(sqlLookup), sqlLookup);
+          // TODO-FIND: handle the case where we request tags from multiple levels
+          SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
+                                      "SELECT publicId, tagGroup, tagElement, value FROM MainDicomTags AS tags "
+                                      "  INNER JOIN FilteredResourcesIds  ON tags.id = FilteredResourcesIds.internalId");
+          formatter.Bind(statement);
+
+          while (statement.Step())
+          {
+            const std::string& resourceId = statement.ColumnString(0);
+            assert(response.HasResource(resourceId));
+            response.GetResource(resourceId).AddStringDicomTag(request.GetLevel(),
+                                                               statement.ColumnInt(1),
+                                                               statement.ColumnInt(2),
+                                                               statement.ColumnString(3));
+          }
+        }
+
+        if (request.IsRetrieveChildrenIdentifiers())
+        {
+          SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
+                                      "SELECT filtered.publicId, childLevel.publicId AS childPublicId "
+                                      "FROM Resources as currentLevel "
+                                      "    INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = currentLevel.internalId "
+                                      "    INNER JOIN Resources childLevel ON childLevel.parentId = currentLevel.internalId");
           formatter.Bind(statement);
 
           while (statement.Step())
           {
-            response.Add(new FindResponse::Resource(request.GetLevel(), statement.ColumnString(0)));
+            const std::string& resourceId = statement.ColumnString(0);
+            assert(response.HasResource(resourceId));
+            response.GetResource(resourceId).AddChildIdentifier(GetChildResourceType(request.GetLevel()), statement.ColumnString(1));
+          }
+        }
+
+        if (request.IsRetrieveParentIdentifier())
+        {
+          SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
+                                      "SELECT filtered.publicId, parentLevel.publicId AS parentPublicId "
+                                      "FROM Resources as currentLevel "
+                                      "    INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = currentLevel.internalId "
+                                      "    INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId");
+
+          while (statement.Step())
+          {
+            const std::string& resourceId = statement.ColumnString(0);
+            const std::string& parentId = statement.ColumnString(1);
+            assert(response.HasResource(resourceId));
+            response.GetResource(resourceId).SetParentIdentifier(parentId);
+          }
+        }
+
+        if (request.IsRetrieveMetadata())
+        {
+          SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
+                                      "SELECT filtered.publicId, metadata.type, metadata.value "
+                                      "FROM Metadata "
+                                      "  INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = Metadata.id");
+
+          while (statement.Step())
+          {
+            const std::string& resourceId = statement.ColumnString(0);
+            assert(response.HasResource(resourceId));
+            response.GetResource(resourceId).AddMetadata(static_cast<MetadataType>(statement.ColumnInt(1)),
+                                                         statement.ColumnString(2));
           }
         }
-        else
+
+        if (request.IsRetrieveLabels())
         {
-          {
-            // first create a temporary table that with the filtered and ordered results
-            sqlLookup = "CREATE TEMPORARY TABLE FilteredResourcesIds AS " + sqlLookup;
-
-            SQLite::Statement statement(db_, SQLITE_FROM_HERE_DYNAMIC(sqlLookup), sqlLookup);
-            formatter.Bind(statement);
-            statement.Run();
-          }
-
-          {
-            // create the response item with the public ids only
-            SQLite::Statement statement(db_, SQLITE_FROM_HERE, "SELECT publicId FROM FilteredResourcesIds");
-            formatter.Bind(statement);
-
-            while (statement.Step())
-            {
-              const std::string resourceId = statement.ColumnString(0);
-              response.Add(new FindResponse::Resource(request.GetLevel(), resourceId));
-            }
-          }
-
-          // request Each response content through INNER JOIN with the temporary table
-          if (request.HasResponseContent(FindRequest::ResponseContent_MainDicomTags))
-          {
-            // TODO-FIND: handle the case where we request tags from multiple levels
-            SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
-                                        "SELECT publicId, tagGroup, tagElement, value FROM MainDicomTags AS tags "
-                                        "  INNER JOIN FilteredResourcesIds  ON tags.id = FilteredResourcesIds.internalId");
-            formatter.Bind(statement);
+          SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
+                                      "SELECT filtered.publicId, label "
+                                      "FROM Labels "
+                                      "  INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = Labels.id");
 
-            while (statement.Step())
-            {
-              const std::string& resourceId = statement.ColumnString(0);
-              assert(response.HasResource(resourceId));
-              response.GetResource(resourceId).AddStringDicomTag(request.GetLevel(),
-                                                                 statement.ColumnInt(1),
-                                                                 statement.ColumnInt(2),
-                                                                 statement.ColumnString(3));
-            }
-          }
-
-          if (request.HasResponseContent(FindRequest::ResponseContent_Children))
+          while (statement.Step())
           {
-            SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
-                                        "SELECT filtered.publicId, childLevel.publicId AS childPublicId "
-                                        "FROM Resources as currentLevel "
-                                        "    INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = currentLevel.internalId "
-                                        "    INNER JOIN Resources childLevel ON childLevel.parentId = currentLevel.internalId");
-            formatter.Bind(statement);
-
-            while (statement.Step())
-            {
-              const std::string& resourceId = statement.ColumnString(0);
-              assert(response.HasResource(resourceId));
-              response.GetResource(resourceId).AddChildIdentifier(GetChildResourceType(request.GetLevel()), statement.ColumnString(1));
-            }
+            const std::string& resourceId = statement.ColumnString(0);
+            assert(response.HasResource(resourceId));
+            response.GetResource(resourceId).AddLabel(statement.ColumnString(1));
           }
-
-          if (request.HasResponseContent(FindRequest::ResponseContent_Parent))
-          {
-            SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
-                                        "SELECT filtered.publicId, parentLevel.publicId AS parentPublicId "
-                                        "FROM Resources as currentLevel "
-                                        "    INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = currentLevel.internalId "
-                                        "    INNER JOIN Resources parentLevel ON currentLevel.parentId = parentLevel.internalId");
+        }
 
-            while (statement.Step())
-            {
-              const std::string& resourceId = statement.ColumnString(0);
-              const std::string& parentId = statement.ColumnString(1);
-              assert(response.HasResource(resourceId));
-              response.GetResource(resourceId).SetParentIdentifier(parentId);
-            }
-          }
-
-          if (request.HasResponseContent(FindRequest::ResponseContent_Metadata))
-          {
-            SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
-                                        "SELECT filtered.publicId, metadata.type, metadata.value "
-                                        "FROM Metadata "
-                                        "  INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = Metadata.id");
-
-            while (statement.Step())
-            {
-              const std::string& resourceId = statement.ColumnString(0);
-              assert(response.HasResource(resourceId));
-              response.GetResource(resourceId).AddMetadata(static_cast<MetadataType>(statement.ColumnInt(1)),
-                                                           statement.ColumnString(2));
-            }
-          }
-
-          if (request.HasResponseContent(FindRequest::ResponseContent_Labels))
-          {
-            SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
-                                        "SELECT filtered.publicId, label "
-                                        "FROM Labels "
-                                        "  INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = Labels.id");
+        if (request.IsRetrieveAttachments())
+        {
+          SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
+                                      "SELECT filtered.publicId, uuid, fileType, uncompressedSize, compressionType, compressedSize, "
+                                      "       uncompressedMD5, compressedMD5 "
+                                      "FROM AttachedFiles "
+                                      "  INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = AttachedFiles.id");
 
-            while (statement.Step())
-            {
-              const std::string& resourceId = statement.ColumnString(0);
-              assert(response.HasResource(resourceId));
-              response.GetResource(resourceId).AddLabel(statement.ColumnString(1));
-            }
-          }
-
-          if (request.HasResponseContent(FindRequest::ResponseContent_Attachments))
+          while (statement.Step())
           {
-            SQLite::Statement statement(db_, SQLITE_FROM_HERE, 
-                                        "SELECT filtered.publicId, uuid, fileType, uncompressedSize, compressionType, compressedSize, "
-                                        "       uncompressedMD5, compressedMD5 "
-                                        "FROM AttachedFiles "
-                                        "  INNER JOIN FilteredResourcesIds filtered ON filtered.internalId = AttachedFiles.id");
+            const std::string& resourceId = statement.ColumnString(0);
+            FileInfo attachment = FileInfo(statement.ColumnString(1),
+                                           static_cast<FileContentType>(statement.ColumnInt(2)),
+                                           statement.ColumnInt64(3),
+                                           statement.ColumnString(6),
+                                           static_cast<CompressionType>(statement.ColumnInt(4)),
+                                           statement.ColumnInt64(5),
+                                           statement.ColumnString(7));
 
-            while (statement.Step())
-            {
-              const std::string& resourceId = statement.ColumnString(0);
-              FileInfo attachment = FileInfo(statement.ColumnString(1),
-                                             static_cast<FileContentType>(statement.ColumnInt(2)),
-                                             statement.ColumnInt64(3),
-                                             statement.ColumnString(6),
-                                             static_cast<CompressionType>(statement.ColumnInt(4)),
-                                             statement.ColumnInt64(5),
-                                             statement.ColumnString(7));
+            assert(response.HasResource(resourceId));
+            response.GetResource(resourceId).AddAttachment(attachment);
+          };
+        }
 
-              assert(response.HasResource(resourceId));
-              response.GetResource(resourceId).AddAttachment(attachment);
-            };
-          }
+        // TODO-FIND: implement other responseContent: ResponseContent_ChildInstanceId, ResponseContent_ChildrenMetadata (later: ResponseContent_IsStable)
 
-          // TODO-FIND: implement other responseContent: ResponseContent_ChildInstanceId, ResponseContent_ChildrenMetadata (later: ResponseContent_IsStable)
-
-        }
       }
 
 #endif
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Fri May 03 17:26:06 2024 +0200
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Fri May 03 18:17:53 2024 +0200
@@ -3877,12 +3877,12 @@
       throw OrthancException(ErrorCode_InternalError);
     }
 
-    if (request.HasResponseContent(FindRequest::ResponseContent_MainDicomTags))
+    if (request.IsRetrieveTagsAtLevel(request.GetLevel()))
     {
       resource.GetDicomTagsAtLevel(tags_, request.GetLevel());
     }
 
-    if (request.HasResponseContent(FindRequest::ResponseContent_Children))
+    if (request.IsRetrieveChildrenIdentifiers())
     {
       const std::set<std::string>& s = resource.GetChildrenIdentifiers(GetChildResourceType(request.GetLevel()));
       for (std::set<std::string>::const_iterator it = s.begin(); it != s.end(); ++it)
@@ -3891,12 +3891,12 @@
       }
     }
 
-    if (request.HasResponseContent(FindRequest::ResponseContent_Parent))
+    if (request.IsRetrieveParentIdentifier())
     {
       parentId_ = resource.GetParentIdentifier();
     }
 
-    if (request.HasResponseContent(FindRequest::ResponseContent_Metadata))
+    if (request.IsRetrieveMetadata())
     {
       metadata_ = resource.GetMetadata();
       std::string value;
@@ -3932,12 +3932,12 @@
       }
     }
 
-    if (request.HasResponseContent(FindRequest::ResponseContent_Labels))
+    if (request.IsRetrieveLabels())
     {
       labels_ = resource.GetLabels();
     }
 
-    if (request.HasResponseContent(FindRequest::ResponseContent_Attachments))
+    if (request.IsRetrieveAttachments())
     {
       FileInfo attachment;
       if (resource.LookupAttachment(attachment, FileContentType_Dicom))
@@ -3947,7 +3947,7 @@
       }
     }
 
-    if (request.HasResponseContent(FindRequest::ResponseContent_ChildrenMetadata))
+    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	Fri May 03 17:26:06 2024 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Fri May 03 18:17:53 2024 +0200
@@ -245,43 +245,34 @@
       if (expand)
       {
         // compatibility with default expand option
-        FindRequest::ResponseContent responseContent = static_cast<FindRequest::ResponseContent>(FindRequest::ResponseContent_MainDicomTags |
-                                   FindRequest::ResponseContent_Metadata |
-                                   FindRequest::ResponseContent_Labels);
-        
-        if (requestedTags.size() > 0 && resourceType != ResourceType_Instance) // if we are requesting specific tags that might be outside of the MainDicomTags, we must get a childInstanceId too
-        {
-          responseContent = static_cast<FindRequest::ResponseContent>(responseContent | FindRequest::ResponseContent_ChildInstanceId);
-        }
+        request.SetRetrieveTagsAtLevel(resourceType, true);
+        request.SetRetrieveMetadata(true);
+        request.SetRetrieveLabels(true);
+
         if (resourceType == ResourceType_Series)
         {
-          responseContent = static_cast<FindRequest::ResponseContent>(responseContent | FindRequest::ResponseContent_ChildrenMetadata); // required for the SeriesStatus
+          request.SetRetrieveChildrenMetadata(true); // required for the SeriesStatus
         }
-        if (resourceType != ResourceType_Instance)
-        {
-          responseContent = static_cast<FindRequest::ResponseContent>(responseContent | FindRequest::ResponseContent_Children);
-        }
+
         if (resourceType == ResourceType_Instance)
         {
-          responseContent = static_cast<FindRequest::ResponseContent>(responseContent | FindRequest::ResponseContent_Attachments); // for FileSize & FileUuid
+          request.SetRetrieveAttachments(true); // for FileSize & FileUuid
         }
+        else
+        {
+          request.SetRetrieveChildrenIdentifiers(true);
+        }
+
         if (resourceType != ResourceType_Patient)
         {
-          responseContent = static_cast<FindRequest::ResponseContent>(responseContent | FindRequest::ResponseContent_Parent);
+          request.SetRetrieveParentIdentifier(true);
         }
 
-        request.SetResponseContent(responseContent);
-        request.SetRetrieveTagsAtLevel(resourceType, true);
-
         if (resourceType == ResourceType_Study)
         {
           request.SetRetrieveTagsAtLevel(ResourceType_Patient, true);
         }
       }
-      else
-      {
-        request.SetResponseContent(FindRequest::ResponseContent_IdentifiersOnly);
-      }
 
       if (call.HasArgument("limit") ||
           call.HasArgument("since"))
@@ -311,18 +302,18 @@
       // TODO-FIND: put this in an AnswerFindResponse method !
       Json::Value answer = Json::arrayValue;
 
-      if (request.IsResponseIdentifiersOnly())
+      if (expand)
       {
         for (size_t i = 0; i < response.GetSize(); i++)
         {
-          answer.append(response.GetResource(i).GetIdentifier());
+          context.AppendFindResponse(answer, request, response.GetResource(i), format, requestedTags, true /* allowStorageAccess */);
         }
       }
       else
       {
         for (size_t i = 0; i < response.GetSize(); i++)
         {
-          context.AppendFindResponse(answer, request, response.GetResource(i), format, requestedTags, true /* allowStorageAccess */);
+          answer.append(response.GetResource(i).GetIdentifier());
         }
       }
 
--- a/OrthancServer/Sources/ServerContext.cpp	Fri May 03 17:26:06 2024 +0200
+++ b/OrthancServer/Sources/ServerContext.cpp	Fri May 03 18:17:53 2024 +0200
@@ -2728,23 +2728,23 @@
     ExpandedResource resource(request, item);
 
     ExpandResourceFlags expandFlags = ExpandResourceFlags_None;
-    if (request.HasResponseContent(FindRequest::ResponseContent_Children))
+    if (request.IsRetrieveChildrenIdentifiers())
     {
       expandFlags = static_cast<ExpandResourceFlags>(expandFlags | ExpandResourceFlags_IncludeChildren);
     }
-    if (request.HasResponseContent(FindRequest::ResponseContent_Metadata))
+    if (request.IsRetrieveMetadata())
     {
       expandFlags = static_cast<ExpandResourceFlags>(expandFlags | ExpandResourceFlags_IncludeAllMetadata | ExpandResourceFlags_IncludeMetadata );
     }
-    if (request.HasResponseContent(FindRequest::ResponseContent_MainDicomTags))
+    if (request.IsRetrieveTagsAtLevel(request.GetLevel()))
     {
       expandFlags = static_cast<ExpandResourceFlags>(expandFlags | ExpandResourceFlags_IncludeMainDicomTags);
     }
-    if (request.HasResponseContent(FindRequest::ResponseContent_IsStable))
+    if (true /* request.HasResponseContent(FindRequest::ResponseContent_IsStable) */)  // TODO-FIND: Is this correct?
     {
       expandFlags = static_cast<ExpandResourceFlags>(expandFlags | ExpandResourceFlags_IncludeIsStable);
     }
-    if (request.HasResponseContent(FindRequest::ResponseContent_Labels))
+    if (request.IsRetrieveLabels())
     {
       expandFlags = static_cast<ExpandResourceFlags>(expandFlags | ExpandResourceFlags_IncludeLabels);
     }