Mercurial > hg > orthanc
changeset 5828:7030fa489669 find-refactoring
tools/find: QueryMetadata
line wrap: on
line diff
--- a/NEWS Mon Oct 07 10:54:40 2024 +0200 +++ b/NEWS Mon Oct 07 15:19:26 2024 +0200 @@ -38,6 +38,7 @@ - 'OrderBy' to order by DICOM Tag or metadata value - 'ParentPatient', 'ParentStudy', 'ParentSeries' to retrieve only descendants of an Orthanc resource. + - 'QueryMetadata' to filter results based on metadata values. Maintenance
--- a/OrthancServer/CMakeLists.txt Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/CMakeLists.txt Mon Oct 07 15:19:26 2024 +0200 @@ -125,8 +125,9 @@ ${CMAKE_SOURCE_DIR}/Sources/OrthancWebDav.cpp ${CMAKE_SOURCE_DIR}/Sources/QueryRetrieveHandler.cpp ${CMAKE_SOURCE_DIR}/Sources/ResourceFinder.cpp - ${CMAKE_SOURCE_DIR}/Sources/Search/DatabaseConstraint.cpp - ${CMAKE_SOURCE_DIR}/Sources/Search/DatabaseConstraints.cpp + ${CMAKE_SOURCE_DIR}/Sources/Search/DatabaseDicomTagConstraint.cpp + ${CMAKE_SOURCE_DIR}/Sources/Search/DatabaseDicomTagConstraints.cpp + ${CMAKE_SOURCE_DIR}/Sources/Search/DatabaseMetadataConstraint.cpp ${CMAKE_SOURCE_DIR}/Sources/Search/DatabaseLookup.cpp ${CMAKE_SOURCE_DIR}/Sources/Search/DicomTagConstraint.cpp ${CMAKE_SOURCE_DIR}/Sources/Search/HierarchicalMatcher.cpp
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -564,7 +564,7 @@ virtual void ApplyLookupResources(std::list<std::string>& resourcesId, std::list<std::string>* instancesId, - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, const std::set<std::string>& labels, LabelsConstraint labelsConstraint,
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -798,7 +798,7 @@ virtual void ApplyLookupResources(std::list<std::string>& resourcesId, std::list<std::string>* instancesId, // Can be NULL if not needed - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, const std::set<std::string>& labels, LabelsConstraint labelsConstraint,
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -136,7 +136,7 @@ static void Convert(DatabasePluginMessages::DatabaseConstraint& target, - const DatabaseConstraint& source) + const DatabaseDicomTagConstraint& source) { target.set_level(Convert(source.GetLevel())); target.set_tag_group(source.GetTag().GetGroup()); @@ -1137,7 +1137,7 @@ virtual void ApplyLookupResources(std::list<std::string>& resourcesId, std::list<std::string>* instancesId, // Can be NULL if not needed - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, const std::set<std::string>& labels, LabelsConstraint labelsConstraint,
--- a/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -74,7 +74,7 @@ } } - void Add(const DatabaseConstraint& constraint) + void Add(const DatabaseDicomTagConstraint& constraint) { constraints_.push_back(new DicomTagConstraint(constraint)); } @@ -84,7 +84,7 @@ static void ApplyIdentifierConstraint(SetOfResources& candidates, ILookupResources& compatibility, - const DatabaseConstraint& constraint, + const DatabaseDicomTagConstraint& constraint, ResourceType level) { std::list<int64_t> matches; @@ -134,8 +134,8 @@ static void ApplyIdentifierRange(SetOfResources& candidates, ILookupResources& compatibility, - const DatabaseConstraint& smaller, - const DatabaseConstraint& greater, + const DatabaseDicomTagConstraint& smaller, + const DatabaseDicomTagConstraint& greater, ResourceType level) { assert(smaller.GetConstraintType() == ConstraintType_SmallerOrEqual && @@ -153,10 +153,10 @@ static void ApplyLevel(SetOfResources& candidates, IDatabaseWrapper::ITransaction& transaction, ILookupResources& compatibility, - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType level) { - typedef std::set<const DatabaseConstraint*> SetOfConstraints; + typedef std::set<const DatabaseDicomTagConstraint*> SetOfConstraints; typedef std::map<DicomTag, SetOfConstraints> Identifiers; // (1) Select which constraints apply to this level, and split @@ -168,7 +168,7 @@ for (size_t i = 0; i < lookup.GetSize(); i++) { - const DatabaseConstraint& constraint = lookup.GetConstraint(i); + const DatabaseDicomTagConstraint& constraint = lookup.GetConstraint(i); if (constraint.GetLevel() == level) { @@ -191,8 +191,8 @@ { // Check whether some range constraint over identifiers is // present at this level - const DatabaseConstraint* smaller = NULL; - const DatabaseConstraint* greater = NULL; + const DatabaseDicomTagConstraint* smaller = NULL; + const DatabaseDicomTagConstraint* greater = NULL; for (SetOfConstraints::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) @@ -308,7 +308,7 @@ void DatabaseLookup::ApplyLookupResources(std::list<std::string>& resourcesId, std::list<std::string>* instancesId, - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, size_t limit) {
--- a/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.h Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/DatabaseLookup.h Mon Oct 07 15:19:26 2024 +0200 @@ -46,7 +46,7 @@ void ApplyLookupResources(std::list<std::string>& resourcesId, std::list<std::string>* instancesId, - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, size_t limit); };
--- a/OrthancServer/Sources/Database/Compatibility/ILookupResources.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/ILookupResources.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -35,7 +35,7 @@ ILookupResources& compatibility, std::list<std::string>& resourcesId, std::list<std::string>* instancesId, - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, size_t limit) {
--- a/OrthancServer/Sources/Database/Compatibility/ILookupResources.h Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/Compatibility/ILookupResources.h Mon Oct 07 15:19:26 2024 +0200 @@ -60,7 +60,7 @@ ILookupResources& compatibility, std::list<std::string>& resourcesId, std::list<std::string>* instancesId, - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, size_t limit); };
--- a/OrthancServer/Sources/Database/FindRequest.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/FindRequest.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -100,8 +100,13 @@ FindRequest::~FindRequest() { + for (std::deque<Ordering*>::iterator it = ordering_.begin(); it != ordering_.end(); ++it) + { + assert(*it != NULL); + delete *it; + } - for (std::deque<Ordering*>::iterator it = ordering_.begin(); it != ordering_.end(); ++it) + for (std::deque<DatabaseMetadataConstraint*>::iterator it = metadataConstraints_.begin(); it != metadataConstraints_.end(); ++it) { assert(*it != NULL); delete *it; @@ -233,6 +238,12 @@ } + void FindRequest::AddMetadataConstraint(DatabaseMetadataConstraint* constraint) + { + metadataConstraints_.push_back(constraint); + } + + void FindRequest::SetRetrieveParentIdentifier(bool retrieve) { if (level_ == ResourceType_Patient)
--- a/OrthancServer/Sources/Database/FindRequest.h Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/FindRequest.h Mon Oct 07 15:19:26 2024 +0200 @@ -24,7 +24,8 @@ #pragma once #include "../../../OrthancFramework/Sources/DicomFormat/DicomTag.h" -#include "../Search/DatabaseConstraints.h" +#include "../Search/DatabaseDicomTagConstraints.h" +#include "../Search/DatabaseMetadataConstraint.h" #include "../Search/DicomTagConstraint.h" #include "../Search/ISqlLookupFormatter.h" #include "../ServerEnumerations.h" @@ -232,16 +233,15 @@ // filter & ordering fields ResourceType level_; // The level of the response (the filtering on tags, labels and metadata also happens at this level) OrthancIdentifiers orthancIdentifiers_; // The response must belong to this Orthanc resources hierarchy - DatabaseConstraints dicomTagConstraints_; // All tags filters (note: the order is not important) + DatabaseDicomTagConstraints dicomTagConstraints_; // All tags filters (note: the order is not important) bool hasLimits_; uint64_t limitsSince_; uint64_t limitsCount_; std::set<std::string> labels_; LabelsConstraint labelsConstraint_; - // TODO-FIND std::deque<Ordering*> ordering_; // The ordering criteria (note: the order is important !) - std::deque<void*> /* TODO-FIND */ metadataConstraints_; // All metadata filters (note: the order is not important) + std::deque<DatabaseMetadataConstraint*> metadataConstraints_; // All metadata filters (note: the order is not important) bool retrieveMainDicomTags_; bool retrieveMetadata_; @@ -284,12 +284,12 @@ return orthancIdentifiers_; } - DatabaseConstraints& GetDicomTagConstraints() + DatabaseDicomTagConstraints& GetDicomTagConstraints() { return dicomTagConstraints_; } - const DatabaseConstraints& GetDicomTagConstraints() const + const DatabaseDicomTagConstraints& GetDicomTagConstraints() const { return dicomTagConstraints_; } @@ -327,6 +327,13 @@ return ordering_; } + void AddMetadataConstraint(DatabaseMetadataConstraint* constraint); + + const std::deque<DatabaseMetadataConstraint*>& GetMetadataConstraint() const + { + return metadataConstraints_; + } + void SetLabels(const std::set<std::string>& labels) { labels_ = labels;
--- a/OrthancServer/Sources/Database/IDatabaseWrapper.h Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/IDatabaseWrapper.h Mon Oct 07 15:19:26 2024 +0200 @@ -39,7 +39,7 @@ namespace Orthanc { - class DatabaseConstraints; + class DatabaseDicomTagConstraints; class ResourcesContent; class IDatabaseWrapper : public boost::noncopyable @@ -308,7 +308,7 @@ virtual void ApplyLookupResources(std::list<std::string>& resourcesId, std::list<std::string>* instancesId, // Can be NULL if not needed - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, const std::set<std::string>& labels, LabelsConstraint labelsConstraint,
--- a/OrthancServer/Sources/Database/MainDicomTagsRegistry.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/MainDicomTagsRegistry.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -98,7 +98,7 @@ } - bool MainDicomTagsRegistry::NormalizeLookup(DatabaseConstraints& target, + bool MainDicomTagsRegistry::NormalizeLookup(DatabaseDicomTagConstraints& target, const DatabaseLookup& source, ResourceType queryLevel) const {
--- a/OrthancServer/Sources/Database/MainDicomTagsRegistry.h Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/MainDicomTagsRegistry.h Mon Oct 07 15:19:26 2024 +0200 @@ -24,7 +24,7 @@ #pragma once #include "../Search/DatabaseLookup.h" -#include "../Search/DatabaseConstraints.h" +#include "../Search/DatabaseDicomTagConstraints.h" #include <boost/noncopyable.hpp> @@ -82,7 +82,7 @@ * constraints are less strict than the original DatabaseLookup, * so more resources will match them. **/ - bool NormalizeLookup(DatabaseConstraints& target, + bool NormalizeLookup(DatabaseDicomTagConstraints& target, const DatabaseLookup& source, ResourceType queryLevel) const; };
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -426,7 +426,7 @@ virtual void ApplyLookupResources(std::list<std::string>& resourcesId, std::list<std::string>* instancesId, - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, const std::set<std::string>& labels, LabelsConstraint labelsConstraint,
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -1593,7 +1593,7 @@ DicomTagConstraint c(tag, ConstraintType_Equal, value, true, true); - DatabaseConstraints query; + DatabaseDicomTagConstraints query; bool isIdentical; // unused query.AddConstraint(c.ConvertToDatabaseConstraint(isIdentical, level, DicomTagType_Identifier)); @@ -1602,12 +1602,12 @@ { private: std::vector<std::string>& result_; - const DatabaseConstraints& query_; + const DatabaseDicomTagConstraints& query_; ResourceType level_; public: Operations(std::vector<std::string>& result, - const DatabaseConstraints& query, + const DatabaseDicomTagConstraints& query, ResourceType level) : result_(result), query_(query), @@ -1893,7 +1893,7 @@ LabelsConstraint labelsConstraint, uint32_t limit) { - class Operations : public ReadOnlyOperationsT6<bool, const DatabaseConstraints&, ResourceType, + class Operations : public ReadOnlyOperationsT6<bool, const DatabaseDicomTagConstraints&, ResourceType, const std::set<std::string>&, LabelsConstraint, size_t> { private: @@ -1939,7 +1939,7 @@ ServerToolbox::CheckValidLabel(*it); } - DatabaseConstraints normalized; + DatabaseDicomTagConstraints normalized; assert(mainDicomTagsRegistry_.get() != NULL); mainDicomTagsRegistry_->NormalizeLookup(normalized, lookup, queryLevel);
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.h Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.h Mon Oct 07 15:19:26 2024 +0200 @@ -221,7 +221,7 @@ void ApplyLookupResources(std::list<std::string>& resourcesId, std::list<std::string>* instancesId, // Can be NULL if not needed - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, const std::set<std::string>& labels, // New in Orthanc 1.12.0 LabelsConstraint labelsConstraint, // New in Orthanc 1.12.0
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -41,6 +41,7 @@ #include "../OrthancConfiguration.h" #include "../Search/DatabaseLookup.h" +#include "../Search/DatabaseMetadataConstraint.h" #include "../ServerContext.h" #include "../ServerToolbox.h" #include "../SliceOrdering.h" @@ -3255,6 +3256,7 @@ static const char* const KEY_PARENT_PATIENT = "ParentPatient"; // New in Orthanc 1.12.5 static const char* const KEY_PARENT_STUDY = "ParentStudy"; // New in Orthanc 1.12.5 static const char* const KEY_PARENT_SERIES = "ParentSeries"; // New in Orthanc 1.12.5 + static const char* const KEY_QUERY_METADATA = "QueryMetadata"; // New in Orthanc 1.12.5 if (call.IsDocumentation()) { @@ -3296,6 +3298,8 @@ "Limit the reported resources to descendants of this study (new in Orthanc 1.12.5)", true) .SetRequestField(KEY_PARENT_SERIES, RestApiCallDocumentation::Type_String, "Limit the reported resources to descendants of this series (new in Orthanc 1.12.5)", true) + .SetRequestField(KEY_QUERY_METADATA, RestApiCallDocumentation::Type_JsonObject, + "Associative array containing the filter on the values of the metadata (new in Orthanc 1.12.5)", true) .AddAnswerType(MimeType_Json, "JSON array containing either the Orthanc identifiers, or detailed information " "about the reported resources (if `Expand` argument is `true`)"); return; @@ -3364,6 +3368,12 @@ throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_ORDER_BY) + "\" must be an array"); } + else if (request.isMember(KEY_QUERY_METADATA) && + request[KEY_QUERY_METADATA].type() != Json::objectValue) + { + throw OrthancException(ErrorCode_BadRequest, + "Field \"" + std::string(KEY_QUERY_METADATA) + "\" must be an JSON object"); + } else if (request.isMember(KEY_PARENT_PATIENT) && request[KEY_PARENT_PATIENT].type() != Json::stringValue) { @@ -3436,30 +3446,66 @@ caseSensitive = request[KEY_CASE_SENSITIVE].asBool(); } - DatabaseLookup query; - - Json::Value::Members members = request[KEY_QUERY].getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - if (request[KEY_QUERY][members[i]].type() != Json::stringValue) + { // DICOM Tag query + DatabaseLookup dicomTagLookup; + + Json::Value::Members members = request[KEY_QUERY].getMemberNames(); + for (size_t i = 0; i < members.size(); i++) { - throw OrthancException(ErrorCode_BadRequest, - "Tag \"" + members[i] + "\" must be associated with a string"); + if (request[KEY_QUERY][members[i]].type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadRequest, + "Tag \"" + members[i] + "\" must be associated with a string"); + } + + const std::string value = request[KEY_QUERY][members[i]].asString(); + + if (!value.empty()) + { + // An empty string corresponds to an universal constraint, + // so we ignore it. This mimics the behavior of class + // "OrthancFindRequestHandler" + dicomTagLookup.AddRestConstraint(FromDcmtkBridge::ParseTag(members[i]), + value, caseSensitive, true); + } } - const std::string value = request[KEY_QUERY][members[i]].asString(); - - if (!value.empty()) + finder.SetDatabaseLookup(dicomTagLookup); + } + + { // Metadata query + Json::Value::Members members = request[KEY_QUERY_METADATA].getMemberNames(); + for (size_t i = 0; i < members.size(); i++) { - // An empty string corresponds to an universal constraint, - // so we ignore it. This mimics the behavior of class - // "OrthancFindRequestHandler" - query.AddRestConstraint(FromDcmtkBridge::ParseTag(members[i]), - value, caseSensitive, true); + if (request[KEY_QUERY_METADATA][members[i]].type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadRequest, + "Tag \"" + members[i] + "\" must be associated with a string"); + } + MetadataType metadata = StringToMetadata(members[i]); + + const std::string value = request[KEY_QUERY_METADATA][members[i]].asString(); + + if (!value.empty()) + { + if (value.find('\\') != std::string::npos) + { + std::vector<std::string> items; + Toolbox::TokenizeString(items, value, '\\'); + + finder.AddMetadataConstraint(new DatabaseMetadataConstraint(metadata, ConstraintType_List, items, caseSensitive)); + } + else if (value.find('*') != std::string::npos || value.find('?') != std::string::npos) + { + finder.AddMetadataConstraint(new DatabaseMetadataConstraint(metadata, ConstraintType_Wildcard, value, caseSensitive)); + } + else + { + finder.AddMetadataConstraint(new DatabaseMetadataConstraint(metadata, ConstraintType_Equal, value, caseSensitive)); + } + } } } - - finder.SetDatabaseLookup(query); } if (request.isMember(KEY_REQUESTED_TAGS))
--- a/OrthancServer/Sources/ResourceFinder.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/ResourceFinder.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -601,7 +601,7 @@ for (size_t i = 0; i < request_.GetDicomTagConstraints().GetSize(); i++) { - const DatabaseConstraint& constraint = request_.GetDicomTagConstraints().GetConstraint(i); + const DatabaseDicomTagConstraint& constraint = request_.GetDicomTagConstraints().GetConstraint(i); if (constraint.GetLevel() == request_.GetLevel()) { request_.SetRetrieveMainDicomTags(true);
--- a/OrthancServer/Sources/ResourceFinder.h Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/ResourceFinder.h Mon Oct 07 15:19:26 2024 +0200 @@ -145,6 +145,10 @@ request_.AddOrdering(metadataType, direction); } + void AddMetadataConstraint(DatabaseMetadataConstraint* constraint) + { + request_.AddMetadataConstraint(constraint); + } void SetLabels(const std::set<std::string>& labels) {
--- a/OrthancServer/Sources/Search/DatabaseConstraint.cpp Mon Oct 07 10:54:40 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "DatabaseConstraint.h" - -#include "../../../OrthancFramework/Sources/OrthancException.h" - -#if ORTHANC_ENABLE_PLUGINS == 1 -# include "../../Plugins/Engine/PluginsEnumerations.h" -#endif - -#include <boost/lexical_cast.hpp> -#include <cassert> - - -namespace Orthanc -{ - DatabaseConstraint::DatabaseConstraint(ResourceType level, - const DicomTag& tag, - bool isIdentifier, - ConstraintType type, - const std::vector<std::string>& values, - bool caseSensitive, - bool mandatory) : - level_(level), - tag_(tag), - isIdentifier_(isIdentifier), - constraintType_(type), - values_(values), - caseSensitive_(caseSensitive), - mandatory_(mandatory) - { - if (type != ConstraintType_List && - values_.size() != 1) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const std::string& DatabaseConstraint::GetValue(size_t index) const - { - if (index >= values_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - return values_[index]; - } - } - - - const std::string& DatabaseConstraint::GetSingleValue() const - { - if (values_.size() != 1) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return values_[0]; - } - } - - -#if ORTHANC_ENABLE_PLUGINS == 1 - void DatabaseConstraint::EncodeForPlugins(OrthancPluginDatabaseConstraint& constraint, - std::vector<const char*>& tmpValues) const - { - memset(&constraint, 0, sizeof(constraint)); - - tmpValues.resize(values_.size()); - - for (size_t i = 0; i < values_.size(); i++) - { - tmpValues[i] = values_[i].c_str(); - } - - constraint.level = Plugins::Convert(level_); - constraint.tagGroup = tag_.GetGroup(); - constraint.tagElement = tag_.GetElement(); - constraint.isIdentifierTag = isIdentifier_; - constraint.isCaseSensitive = caseSensitive_; - constraint.isMandatory = mandatory_; - constraint.type = Plugins::Convert(constraintType_); - constraint.valuesCount = values_.size(); - constraint.values = (tmpValues.empty() ? NULL : &tmpValues[0]); - } -#endif -}
--- a/OrthancServer/Sources/Search/DatabaseConstraint.h Mon Oct 07 10:54:40 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "../../../OrthancFramework/Sources/DicomFormat/DicomMap.h" -#include "../ServerEnumerations.h" - -#if ORTHANC_ENABLE_PLUGINS == 1 -# include "../../Plugins/Include/orthanc/OrthancCDatabasePlugin.h" -#endif - -namespace Orthanc -{ - class DatabaseConstraint : public boost::noncopyable - { - private: - ResourceType level_; - DicomTag tag_; - bool isIdentifier_; - ConstraintType constraintType_; - std::vector<std::string> values_; - bool caseSensitive_; - bool mandatory_; - - public: - DatabaseConstraint(ResourceType level, - const DicomTag& tag, - bool isIdentifier, - ConstraintType type, - const std::vector<std::string>& values, - bool caseSensitive, - bool mandatory); - - ResourceType GetLevel() const - { - return level_; - } - - const DicomTag& GetTag() const - { - return tag_; - } - - bool IsIdentifier() const - { - return isIdentifier_; - } - - ConstraintType GetConstraintType() const - { - return constraintType_; - } - - size_t GetValuesCount() const - { - return values_.size(); - } - - const std::string& GetValue(size_t index) const; - - const std::string& GetSingleValue() const; - - bool IsCaseSensitive() const - { - return caseSensitive_; - } - - bool IsMandatory() const - { - return mandatory_; - } - - bool IsMatch(const DicomMap& dicom) const; - -#if ORTHANC_ENABLE_PLUGINS == 1 - void EncodeForPlugins(OrthancPluginDatabaseConstraint& constraint, - std::vector<const char*>& tmpValues) const; -#endif - }; -}
--- a/OrthancServer/Sources/Search/DatabaseConstraints.cpp Mon Oct 07 10:54:40 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "DatabaseConstraints.h" - -#include "../../../OrthancFramework/Sources/OrthancException.h" - -#include <boost/lexical_cast.hpp> -#include <cassert> - - -namespace Orthanc -{ - void DatabaseConstraints::Clear() - { - for (size_t i = 0; i < constraints_.size(); i++) - { - assert(constraints_[i] != NULL); - delete constraints_[i]; - } - - constraints_.clear(); - } - - - void DatabaseConstraints::AddConstraint(DatabaseConstraint* constraint) - { - if (constraint == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - else - { - constraints_.push_back(constraint); - } - } - - - const DatabaseConstraint& DatabaseConstraints::GetConstraint(size_t index) const - { - if (index >= constraints_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - assert(constraints_[index] != NULL); - return *constraints_[index]; - } - } - - - std::string DatabaseConstraints::Format() const - { - std::string s; - - for (size_t i = 0; i < constraints_.size(); i++) - { - assert(constraints_[i] != NULL); - const DatabaseConstraint& constraint = *constraints_[i]; - s += "Constraint " + boost::lexical_cast<std::string>(i) + " at " + EnumerationToString(constraint.GetLevel()) + - ": " + constraint.GetTag().Format(); - - switch (constraint.GetConstraintType()) - { - case ConstraintType_Equal: - s += " == " + constraint.GetSingleValue(); - break; - - case ConstraintType_SmallerOrEqual: - s += " <= " + constraint.GetSingleValue(); - break; - - case ConstraintType_GreaterOrEqual: - s += " >= " + constraint.GetSingleValue(); - break; - - case ConstraintType_Wildcard: - s += " ~~ " + constraint.GetSingleValue(); - break; - - case ConstraintType_List: - { - s += " in [ "; - bool first = true; - for (size_t j = 0; j < constraint.GetValuesCount(); j++) - { - if (first) - { - first = false; - } - else - { - s += ", "; - } - s += constraint.GetValue(j); - } - s += "]"; - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - - s += "\n"; - } - - return s; - } -}
--- a/OrthancServer/Sources/Search/DatabaseConstraints.h Mon Oct 07 10:54:40 2024 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "DatabaseConstraint.h" - -#include <deque> - -namespace Orthanc -{ - class DatabaseConstraints : public boost::noncopyable - { - private: - std::deque<DatabaseConstraint*> constraints_; - - public: - ~DatabaseConstraints() - { - Clear(); - } - - void Clear(); - - void AddConstraint(DatabaseConstraint* constraint); // Takes ownership - - bool IsEmpty() const - { - return constraints_.empty(); - } - - size_t GetSize() const - { - return constraints_.size(); - } - - const DatabaseConstraint& GetConstraint(size_t index) const; - - std::string Format() const; - }; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/Search/DatabaseDicomTagConstraint.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -0,0 +1,112 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeadersServer.h" +#include "DatabaseDicomTagConstraint.h" + +#include "../../../OrthancFramework/Sources/OrthancException.h" + +#if ORTHANC_ENABLE_PLUGINS == 1 +# include "../../Plugins/Engine/PluginsEnumerations.h" +#endif + +#include <boost/lexical_cast.hpp> +#include <cassert> + + +namespace Orthanc +{ + DatabaseDicomTagConstraint::DatabaseDicomTagConstraint(ResourceType level, + const DicomTag& tag, + bool isIdentifier, + ConstraintType type, + const std::vector<std::string>& values, + bool caseSensitive, + bool mandatory) : + level_(level), + tag_(tag), + isIdentifier_(isIdentifier), + constraintType_(type), + values_(values), + caseSensitive_(caseSensitive), + mandatory_(mandatory) + { + if (type != ConstraintType_List && + values_.size() != 1) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + const std::string& DatabaseDicomTagConstraint::GetValue(size_t index) const + { + if (index >= values_.size()) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + else + { + return values_[index]; + } + } + + + const std::string& DatabaseDicomTagConstraint::GetSingleValue() const + { + if (values_.size() != 1) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + return values_[0]; + } + } + + +#if ORTHANC_ENABLE_PLUGINS == 1 + void DatabaseDicomTagConstraint::EncodeForPlugins(OrthancPluginDatabaseConstraint& constraint, + std::vector<const char*>& tmpValues) const + { + memset(&constraint, 0, sizeof(constraint)); + + tmpValues.resize(values_.size()); + + for (size_t i = 0; i < values_.size(); i++) + { + tmpValues[i] = values_[i].c_str(); + } + + constraint.level = Plugins::Convert(level_); + constraint.tagGroup = tag_.GetGroup(); + constraint.tagElement = tag_.GetElement(); + constraint.isIdentifierTag = isIdentifier_; + constraint.isCaseSensitive = caseSensitive_; + constraint.isMandatory = mandatory_; + constraint.type = Plugins::Convert(constraintType_); + constraint.valuesCount = values_.size(); + constraint.values = (tmpValues.empty() ? NULL : &tmpValues[0]); + } +#endif +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/Search/DatabaseDicomTagConstraint.h Mon Oct 07 15:19:26 2024 +0200 @@ -0,0 +1,101 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../../../OrthancFramework/Sources/DicomFormat/DicomMap.h" +#include "../ServerEnumerations.h" +#include "IDatabaseConstraint.h" + +#if ORTHANC_ENABLE_PLUGINS == 1 +# include "../../Plugins/Include/orthanc/OrthancCDatabasePlugin.h" +#endif + +namespace Orthanc +{ + class DatabaseDicomTagConstraint : public IDatabaseConstraint + { + private: + ResourceType level_; + DicomTag tag_; + bool isIdentifier_; + ConstraintType constraintType_; + std::vector<std::string> values_; + bool caseSensitive_; + bool mandatory_; + + public: + DatabaseDicomTagConstraint(ResourceType level, + const DicomTag& tag, + bool isIdentifier, + ConstraintType type, + const std::vector<std::string>& values, + bool caseSensitive, + bool mandatory); + + ResourceType GetLevel() const + { + return level_; + } + + const DicomTag& GetTag() const + { + return tag_; + } + + bool IsIdentifier() const + { + return isIdentifier_; + } + + virtual ConstraintType GetConstraintType() const ORTHANC_OVERRIDE + { + return constraintType_; + } + + virtual size_t GetValuesCount() const ORTHANC_OVERRIDE + { + return values_.size(); + } + + virtual const std::string& GetValue(size_t index) const ORTHANC_OVERRIDE; + + virtual const std::string& GetSingleValue() const ORTHANC_OVERRIDE; + + virtual bool IsCaseSensitive() const ORTHANC_OVERRIDE + { + return caseSensitive_; + } + + virtual bool IsMandatory() const ORTHANC_OVERRIDE + { + return mandatory_; + } + + +#if ORTHANC_ENABLE_PLUGINS == 1 + void EncodeForPlugins(OrthancPluginDatabaseConstraint& constraint, + std::vector<const char*>& tmpValues) const; +#endif + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/Search/DatabaseDicomTagConstraints.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -0,0 +1,132 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeadersServer.h" +#include "DatabaseDicomTagConstraints.h" + +#include "../../../OrthancFramework/Sources/OrthancException.h" + +#include <boost/lexical_cast.hpp> +#include <cassert> + + +namespace Orthanc +{ + void DatabaseDicomTagConstraints::Clear() + { + for (size_t i = 0; i < constraints_.size(); i++) + { + assert(constraints_[i] != NULL); + delete constraints_[i]; + } + + constraints_.clear(); + } + + + void DatabaseDicomTagConstraints::AddConstraint(DatabaseDicomTagConstraint* constraint) + { + if (constraint == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + else + { + constraints_.push_back(constraint); + } + } + + + const DatabaseDicomTagConstraint& DatabaseDicomTagConstraints::GetConstraint(size_t index) const + { + if (index >= constraints_.size()) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + else + { + assert(constraints_[index] != NULL); + return *constraints_[index]; + } + } + + + std::string DatabaseDicomTagConstraints::Format() const + { + std::string s; + + for (size_t i = 0; i < constraints_.size(); i++) + { + assert(constraints_[i] != NULL); + const DatabaseDicomTagConstraint& constraint = *constraints_[i]; + s += "Constraint " + boost::lexical_cast<std::string>(i) + " at " + EnumerationToString(constraint.GetLevel()) + + ": " + constraint.GetTag().Format(); + + switch (constraint.GetConstraintType()) + { + case ConstraintType_Equal: + s += " == " + constraint.GetSingleValue(); + break; + + case ConstraintType_SmallerOrEqual: + s += " <= " + constraint.GetSingleValue(); + break; + + case ConstraintType_GreaterOrEqual: + s += " >= " + constraint.GetSingleValue(); + break; + + case ConstraintType_Wildcard: + s += " ~~ " + constraint.GetSingleValue(); + break; + + case ConstraintType_List: + { + s += " in [ "; + bool first = true; + for (size_t j = 0; j < constraint.GetValuesCount(); j++) + { + if (first) + { + first = false; + } + else + { + s += ", "; + } + s += constraint.GetValue(j); + } + s += "]"; + break; + } + + default: + throw OrthancException(ErrorCode_InternalError); + } + + s += "\n"; + } + + return s; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/Search/DatabaseDicomTagConstraints.h Mon Oct 07 15:19:26 2024 +0200 @@ -0,0 +1,61 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "DatabaseDicomTagConstraint.h" + +#include <deque> + +namespace Orthanc +{ + class DatabaseDicomTagConstraints : public boost::noncopyable + { + private: + std::deque<DatabaseDicomTagConstraint*> constraints_; + + public: + ~DatabaseDicomTagConstraints() + { + Clear(); + } + + void Clear(); + + void AddConstraint(DatabaseDicomTagConstraint* constraint); // Takes ownership + + bool IsEmpty() const + { + return constraints_.empty(); + } + + size_t GetSize() const + { + return constraints_.size(); + } + + const DatabaseDicomTagConstraint& GetConstraint(size_t index) const; + + std::string Format() const; + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/Search/DatabaseMetadataConstraint.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -0,0 +1,93 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeadersServer.h" +#include "DatabaseMetadataConstraint.h" + +#include "../../../OrthancFramework/Sources/OrthancException.h" + +#include <boost/lexical_cast.hpp> +#include <cassert> + + +namespace Orthanc +{ + DatabaseMetadataConstraint::DatabaseMetadataConstraint(MetadataType metadata, + ConstraintType type, + const std::vector<std::string>& values, + bool caseSensitive) : + metadata_(metadata), + constraintType_(type), + values_(values), + caseSensitive_(caseSensitive) + { + if (type != ConstraintType_List && + values_.size() != 1) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + DatabaseMetadataConstraint::DatabaseMetadataConstraint(MetadataType metadata, + ConstraintType type, + const std::string& value, + bool caseSensitive) : + metadata_(metadata), + constraintType_(type), + caseSensitive_(caseSensitive) + { + if (type == ConstraintType_List) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + values_.push_back(value); + } + + const std::string& DatabaseMetadataConstraint::GetValue(size_t index) const + { + if (index >= values_.size()) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + else + { + return values_[index]; + } + } + + + const std::string& DatabaseMetadataConstraint::GetSingleValue() const + { + if (values_.size() != 1) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + return values_[0]; + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/Search/DatabaseMetadataConstraint.h Mon Oct 07 15:19:26 2024 +0200 @@ -0,0 +1,81 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../../../OrthancFramework/Sources/DicomFormat/DicomMap.h" +#include "../ServerEnumerations.h" +#include "IDatabaseConstraint.h" + +namespace Orthanc +{ + class DatabaseMetadataConstraint : public IDatabaseConstraint + { + private: + MetadataType metadata_; + ConstraintType constraintType_; + std::vector<std::string> values_; + bool caseSensitive_; + + public: + DatabaseMetadataConstraint(MetadataType metadata, + ConstraintType type, + const std::string& value, + bool caseSensitive); + + DatabaseMetadataConstraint(MetadataType metadata, + ConstraintType type, + const std::vector<std::string>& values, + bool caseSensitive); + + const MetadataType& GetMetadata() const + { + return metadata_; + } + + virtual ConstraintType GetConstraintType() const ORTHANC_OVERRIDE + { + return constraintType_; + } + + virtual size_t GetValuesCount() const ORTHANC_OVERRIDE + { + return values_.size(); + } + + virtual const std::string& GetValue(size_t index) const ORTHANC_OVERRIDE; + + virtual const std::string& GetSingleValue() const ORTHANC_OVERRIDE; + + virtual bool IsCaseSensitive() const ORTHANC_OVERRIDE + { + return caseSensitive_; + } + + virtual bool IsMandatory() const ORTHANC_OVERRIDE + { + return true; + } + + }; +}
--- a/OrthancServer/Sources/Search/DicomTagConstraint.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Search/DicomTagConstraint.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -30,7 +30,7 @@ #include "../../../OrthancFramework/Sources/OrthancException.h" #include "../../../OrthancFramework/Sources/Toolbox.h" -#include "DatabaseConstraint.h" +#include "DatabaseDicomTagConstraint.h" #include <boost/regex.hpp> @@ -154,7 +154,7 @@ } - DicomTagConstraint::DicomTagConstraint(const DatabaseConstraint& constraint) : + DicomTagConstraint::DicomTagConstraint(const DatabaseDicomTagConstraint& constraint) : tag_(constraint.GetTag()), constraintType_(constraint.GetConstraintType()), caseSensitive_(constraint.IsCaseSensitive()), @@ -369,9 +369,9 @@ } - DatabaseConstraint* DicomTagConstraint::ConvertToDatabaseConstraint(bool& isIdentical, - ResourceType level, - DicomTagType tagType) const + DatabaseDicomTagConstraint* DicomTagConstraint::ConvertToDatabaseConstraint(bool& isIdentical, + ResourceType level, + DicomTagType tagType) const { bool isIdentifier, caseSensitive; @@ -415,7 +415,7 @@ } } - return new DatabaseConstraint(level, tag_, isIdentifier, constraintType_, - values, caseSensitive, mandatory_); + return new DatabaseDicomTagConstraint(level, tag_, isIdentifier, constraintType_, + values, caseSensitive, mandatory_); } }
--- a/OrthancServer/Sources/Search/DicomTagConstraint.h Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Search/DicomTagConstraint.h Mon Oct 07 15:19:26 2024 +0200 @@ -25,7 +25,7 @@ #include "../ServerEnumerations.h" #include "../../../OrthancFramework/Sources/DicomFormat/DicomMap.h" -#include "DatabaseConstraint.h" +#include "DatabaseDicomTagConstraint.h" #include <boost/shared_ptr.hpp> @@ -62,7 +62,7 @@ explicit DicomTagConstraint(const DicomTagConstraint& other); - explicit DicomTagConstraint(const DatabaseConstraint& constraint); + explicit DicomTagConstraint(const DatabaseDicomTagConstraint& constraint); const DicomTag& GetTag() const { @@ -109,8 +109,8 @@ std::string Format() const; - DatabaseConstraint* ConvertToDatabaseConstraint(bool& isIdentical /* out */, - ResourceType level, - DicomTagType tagType) const; + DatabaseDicomTagConstraint* ConvertToDatabaseConstraint(bool& isIdentical /* out */, + ResourceType level, + DicomTagType tagType) const; }; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/Search/IDatabaseConstraint.h Mon Oct 07 15:19:26 2024 +0200 @@ -0,0 +1,50 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../ServerEnumerations.h" +#include <boost/noncopyable.hpp> + +namespace Orthanc +{ + class IDatabaseConstraint : public boost::noncopyable + { + public: + virtual ~IDatabaseConstraint() + { + } + + virtual ConstraintType GetConstraintType() const = 0; + + virtual size_t GetValuesCount() const = 0; + + virtual const std::string& GetValue(size_t index) const = 0; + + virtual const std::string& GetSingleValue() const = 0; + + virtual bool IsCaseSensitive() const = 0; + + virtual bool IsMandatory() const = 0; + }; +}
--- a/OrthancServer/Sources/Search/ISqlLookupFormatter.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Search/ISqlLookupFormatter.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -27,7 +27,7 @@ #include "../../../OrthancFramework/Sources/OrthancException.h" #include "../../../OrthancFramework/Sources/Toolbox.h" #include "../Database/FindRequest.h" -#include "DatabaseConstraint.h" +#include "DatabaseDicomTagConstraint.h" #include "../Database/MainDicomTagsRegistry.h" #include <cassert> @@ -82,7 +82,7 @@ static bool FormatComparison(std::string& target, ISqlLookupFormatter& formatter, - const DatabaseConstraint& constraint, + const IDatabaseConstraint& constraint, size_t index, bool escapeBrackets) { @@ -254,7 +254,7 @@ static void FormatJoin(std::string& target, - const DatabaseConstraint& constraint, + const DatabaseDicomTagConstraint& constraint, size_t index) { std::string tag = "t" + boost::lexical_cast<std::string>(index); @@ -284,6 +284,29 @@ boost::lexical_cast<std::string>(constraint.GetTag().GetElement())); } + static void FormatJoin(std::string& target, + const DatabaseMetadataConstraint& constraint, + ResourceType level, + size_t index) + { + std::string tag = "t" + boost::lexical_cast<std::string>(index); + + if (constraint.IsMandatory()) + { + target = " INNER JOIN "; + } + else + { + target = " LEFT JOIN "; + } + + target += "Metadata "; + + target += tag + " ON " + tag + ".id = " + FormatLevel(level) + + ".internalId AND " + tag + ".type = " + + boost::lexical_cast<std::string>(constraint.GetMetadata()); + } + static void FormatJoinForOrdering(std::string& target, const DicomTag& tag, @@ -388,7 +411,7 @@ static bool FormatComparison2(std::string& target, ISqlLookupFormatter& formatter, - const DatabaseConstraint& constraint, + const DatabaseDicomTagConstraint& constraint, bool escapeBrackets) { std::string comparison; @@ -558,7 +581,7 @@ void ISqlLookupFormatter::GetLookupLevels(ResourceType& lowerLevel, ResourceType& upperLevel, const ResourceType& queryLevel, - const DatabaseConstraints& lookup) + const DatabaseDicomTagConstraints& lookup) { assert(ResourceType_Patient < ResourceType_Study && ResourceType_Study < ResourceType_Series && @@ -586,12 +609,13 @@ void ISqlLookupFormatter::Apply(std::string& sql, ISqlLookupFormatter& formatter, - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, const std::set<std::string>& labels, LabelsConstraint labelsConstraint, size_t limit) { + // get the limit levels of the DICOM Tags lookup ResourceType lowerLevel, upperLevel; GetLookupLevels(lowerLevel, upperLevel, queryLevel, lookup); @@ -606,7 +630,7 @@ for (size_t i = 0; i < lookup.GetSize(); i++) { - const DatabaseConstraint& constraint = lookup.GetConstraint(i); + const DatabaseDicomTagConstraint& constraint = lookup.GetConstraint(i); std::string comparison; @@ -798,10 +822,10 @@ size_t count = 0; - const DatabaseConstraints& dicomTagsConstraints = request.GetDicomTagConstraints(); + const DatabaseDicomTagConstraints& dicomTagsConstraints = request.GetDicomTagConstraints(); for (size_t i = 0; i < dicomTagsConstraints.GetSize(); i++) { - const DatabaseConstraint& constraint = dicomTagsConstraints.GetConstraint(i); + const DatabaseDicomTagConstraint& constraint = dicomTagsConstraints.GetConstraint(i); std::string comparison; @@ -820,6 +844,25 @@ } } + for (std::deque<DatabaseMetadataConstraint*>::const_iterator it = request.GetMetadataConstraint().begin(); it != request.GetMetadataConstraint().end(); ++it) + { + std::string comparison; + + if (FormatComparison(comparison, formatter, *(*it), count, escapeBrackets)) + { + std::string join; + FormatJoin(join, *(*it), request.GetLevel(), count); + joins += join; + + if (!comparison.empty()) + { + comparisons += " AND " + comparison; + } + + count ++; + } + } + for (int level = queryLevel - 1; level >= upperLevel; level--) { sql += (" INNER JOIN Resources " + @@ -891,7 +934,7 @@ void ISqlLookupFormatter::ApplySingleLevel(std::string& sql, ISqlLookupFormatter& formatter, - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, const std::set<std::string>& labels, LabelsConstraint labelsConstraint, @@ -910,7 +953,7 @@ for (size_t i = 0; i < lookup.GetSize(); i++) { - const DatabaseConstraint& constraint = lookup.GetConstraint(i); + const DatabaseDicomTagConstraint& constraint = lookup.GetConstraint(i); std::string comparison;
--- a/OrthancServer/Sources/Search/ISqlLookupFormatter.h Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/Sources/Search/ISqlLookupFormatter.h Mon Oct 07 15:19:26 2024 +0200 @@ -30,7 +30,7 @@ namespace Orthanc { - class DatabaseConstraints; + class DatabaseDicomTagConstraints; class FindRequest; enum LabelsConstraint @@ -65,11 +65,11 @@ static void GetLookupLevels(ResourceType& lowerLevel, ResourceType& upperLevel, const ResourceType& queryLevel, - const DatabaseConstraints& lookup); + const DatabaseDicomTagConstraints& lookup); static void Apply(std::string& sql, ISqlLookupFormatter& formatter, - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, const std::set<std::string>& labels, // New in Orthanc 1.12.0 LabelsConstraint labelsConstraint, // New in Orthanc 1.12.0 @@ -77,7 +77,7 @@ static void ApplySingleLevel(std::string& sql, ISqlLookupFormatter& formatter, - const DatabaseConstraints& lookup, + const DatabaseDicomTagConstraints& lookup, ResourceType queryLevel, const std::set<std::string>& labels, // New in Orthanc 1.12.0 LabelsConstraint labelsConstraint, // New in Orthanc 1.12.0
--- a/OrthancServer/UnitTestsSources/ServerIndexTests.cpp Mon Oct 07 10:54:40 2024 +0200 +++ b/OrthancServer/UnitTestsSources/ServerIndexTests.cpp Mon Oct 07 15:19:26 2024 +0200 @@ -166,7 +166,7 @@ DicomTagConstraint c(tag, type, value, true, true); - DatabaseConstraints lookup; + DatabaseDicomTagConstraints lookup; bool isEquivalent; // unused lookup.AddConstraint(c.ConvertToDatabaseConstraint(isEquivalent, level, DicomTagType_Identifier)); @@ -187,7 +187,7 @@ DicomTagConstraint c1(tag, type1, value1, true, true); DicomTagConstraint c2(tag, type2, value2, true, true); - DatabaseConstraints lookup; + DatabaseDicomTagConstraints lookup; bool isEquivalent; // unused lookup.AddConstraint(c1.ConvertToDatabaseConstraint(isEquivalent, level, DicomTagType_Identifier)); lookup.AddConstraint(c2.ConvertToDatabaseConstraint(isEquivalent, level, DicomTagType_Identifier));