# HG changeset patch # User Alain Mazy # Date 1714141938 -7200 # Node ID 5a13483d12c58fbafbd98eb075525f413bd1596b # Parent 738f80622e9129766844884e258ab5ef9cd5f298 find-refactoring: attachments diff -r 738f80622e91 -r 5a13483d12c5 NEWS --- a/NEWS Thu Apr 25 17:07:33 2024 +0200 +++ b/NEWS Fri Apr 26 16:32:18 2024 +0200 @@ -27,7 +27,7 @@ in case you just want to update the MainDicomTags of that resource level only e.g. after you have updated the 'ExtraMainDicomTags' for this level. * TODO-FIND: complete the list of updated routes: - /studies?expand and sibbling routes now also return "Metadata" + /studies?expand and sibbling routes now also return "Metadata" (if the DB implements 'extended-api-v1') Plugins ------- diff -r 738f80622e91 -r 5a13483d12c5 OrthancServer/Sources/Database/FindRequest.h --- a/OrthancServer/Sources/Database/FindRequest.h Thu Apr 25 17:07:33 2024 +0200 +++ b/OrthancServer/Sources/Database/FindRequest.h Fri Apr 26 16:32:18 2024 +0200 @@ -49,7 +49,8 @@ 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_IsStable = (1 << 7), // This is currently not saved in DB but it could be in the future. + 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. ResponseContent_IdentifiersOnly = 0, ResponseContent_INTERNAL = 0x7FFFFFFF diff -r 738f80622e91 -r 5a13483d12c5 OrthancServer/Sources/Database/FindResponse.h --- a/OrthancServer/Sources/Database/FindResponse.h Thu Apr 25 17:07:33 2024 +0200 +++ b/OrthancServer/Sources/Database/FindResponse.h Fri Apr 26 16:32:18 2024 +0200 @@ -23,6 +23,8 @@ #pragma once #include "../../../OrthancFramework/Sources/DicomFormat/DicomMap.h" +#include "../../../OrthancFramework/Sources/Enumerations.h" +#include "../../../OrthancFramework/Sources/FileStorage/FileInfo.h" #include "../ServerEnumerations.h" #include "OrthancIdentifiers.h" #include "FindRequest.h" @@ -90,7 +92,7 @@ std::string childInstanceId_; std::set labels_; std::map metadata_; - std::map attachments_; + std::map attachments_; public: Item(FindRequest::ResponseContent responseContent, @@ -194,6 +196,29 @@ { return labels_; } + + void AddAttachment(const FileInfo& attachment) + { + attachments_[attachment.GetContentType()] = attachment; + } + + const std::map& GetAttachments() const + { + return attachments_; + } + + bool LookupAttachment(FileInfo& target, FileContentType type) const + { + std::map::const_iterator it = attachments_.find(type); + if (it != attachments_.end()) + { + target = it->second; + return true; + } + + return false; + } + // TODO-FIND: add other getters and setters }; diff -r 738f80622e91 -r 5a13483d12c5 OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp --- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp Thu Apr 25 17:07:33 2024 +0200 +++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp Fri Apr 26 16:32:18 2024 +0200 @@ -1285,7 +1285,29 @@ } } - // TODO-FIND: implement other responseContent: ResponseContent_ChildInstanceId, ResponseContent_Attachments, (later: ResponseContent_IsStable) + if (request.HasResponseContent(FindRequest::ResponseContent_Attachments)) + { + 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); + FileInfo attachment = FileInfo(statement.ColumnString(1), + static_cast(statement.ColumnInt(2)), + statement.ColumnInt64(3), + statement.ColumnString(6), + static_cast(statement.ColumnInt(4)), + statement.ColumnInt64(5), + statement.ColumnString(7)); + items[resourceId]->AddAttachment(attachment); + }; + } + + // TODO-FIND: implement other responseContent: ResponseContent_ChildInstanceId, ResponseContent_ChildrenMetadata (later: ResponseContent_IsStable) } } diff -r 738f80622e91 -r 5a13483d12c5 OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp --- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Thu Apr 25 17:07:33 2024 +0200 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Fri Apr 26 16:32:18 2024 +0200 @@ -3926,6 +3926,24 @@ { labels_ = item.GetLabels(); } - // TODO-FIND: continue: isStable_, satus_, fileSize_, fileUuid_ + + if (item.HasResponseContent(FindRequest::ResponseContent_Attachments)) + { + FileInfo attachment; + if (item.LookupAttachment(attachment, FileContentType_Dicom)) + { + fileSize_ = attachment.GetUncompressedSize(); + fileUuid_ = attachment.GetUuid(); + } + } + + if (item.HasResponseContent(FindRequest::ResponseContent_ChildrenMetadata)) + { + // 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 + // to compute it AFAP and we should compute it only if the user request it ! + } + + // TODO-FIND: continue: isStable_, status_ } } diff -r 738f80622e91 -r 5a13483d12c5 OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp --- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Thu Apr 25 17:07:33 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Fri Apr 26 16:32:18 2024 +0200 @@ -230,20 +230,47 @@ * EXPERIMENTAL VERSION **/ + // TODO-FIND: include the FindRequest options parsing in a method (parse from get-arguments and from post payload) + // TODO-FIND: support other values for expand like expand=MainDicomTags,Labels,Parent,SeriesStatus const bool expand = (call.HasArgument("expand") && call.GetBooleanArgument("expand", true)); + std::set requestedTags; + OrthancRestApi::GetRequestedTags(requestedTags, call); + + const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); + FindRequest request(resourceType); if (expand) { - request.SetResponseContent(static_cast(FindRequest::ResponseContent_MainDicomTags | + // compatibility with default expand option + FindRequest::ResponseContent responseContent = static_cast(FindRequest::ResponseContent_MainDicomTags | FindRequest::ResponseContent_Metadata | - FindRequest::ResponseContent_Labels | - FindRequest::ResponseContent_Attachments | - FindRequest::ResponseContent_Parent | - FindRequest::ResponseContent_Children)); - + 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(responseContent | FindRequest::ResponseContent_ChildInstanceId); + } + if (resourceType == ResourceType_Series) + { + responseContent = static_cast(responseContent | FindRequest::ResponseContent_ChildrenMetadata); // required for the SeriesStatus + } + if (resourceType != ResourceType_Instance) + { + responseContent = static_cast(responseContent | FindRequest::ResponseContent_Children); + } + if (resourceType == ResourceType_Instance) + { + responseContent = static_cast(responseContent | FindRequest::ResponseContent_Attachments); // for FileSize & FileUuid + } + if (resourceType != ResourceType_Patient) + { + responseContent = static_cast(responseContent | FindRequest::ResponseContent_Parent); + } + + request.SetResponseContent(responseContent); request.SetRetrieveTagsAtLevel(resourceType, true); if (resourceType == ResourceType_Study) @@ -294,11 +321,6 @@ } else { - std::set requestedTags; - OrthancRestApi::GetRequestedTags(requestedTags, call); - - const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); - for (size_t i = 0; i < response.GetSize(); i++) { context.AppendFindResponse(answer, response.GetItem(i), format, requestedTags, true /* allowStorageAccess */);