Mercurial > hg > orthanc
comparison OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp @ 5828:7030fa489669 find-refactoring
tools/find: QueryMetadata
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Mon, 07 Oct 2024 15:19:26 +0200 |
parents | d73dfb4548c6 |
children | 963945d780d6 |
comparison
equal
deleted
inserted
replaced
5827:976872a99d39 | 5828:7030fa489669 |
---|---|
39 #include "../../../OrthancFramework/Sources/MultiThreading/Semaphore.h" | 39 #include "../../../OrthancFramework/Sources/MultiThreading/Semaphore.h" |
40 #include "../../../OrthancFramework/Sources/SerializationToolbox.h" | 40 #include "../../../OrthancFramework/Sources/SerializationToolbox.h" |
41 | 41 |
42 #include "../OrthancConfiguration.h" | 42 #include "../OrthancConfiguration.h" |
43 #include "../Search/DatabaseLookup.h" | 43 #include "../Search/DatabaseLookup.h" |
44 #include "../Search/DatabaseMetadataConstraint.h" | |
44 #include "../ServerContext.h" | 45 #include "../ServerContext.h" |
45 #include "../ServerToolbox.h" | 46 #include "../ServerToolbox.h" |
46 #include "../SliceOrdering.h" | 47 #include "../SliceOrdering.h" |
47 | 48 |
48 // This "include" is mandatory for Release builds using Linux Standard Base | 49 // This "include" is mandatory for Release builds using Linux Standard Base |
3253 static const char* const KEY_ORDER_BY_TYPE = "Type"; // New in Orthanc 1.12.5 | 3254 static const char* const KEY_ORDER_BY_TYPE = "Type"; // New in Orthanc 1.12.5 |
3254 static const char* const KEY_ORDER_BY_DIRECTION = "Direction"; // New in Orthanc 1.12.5 | 3255 static const char* const KEY_ORDER_BY_DIRECTION = "Direction"; // New in Orthanc 1.12.5 |
3255 static const char* const KEY_PARENT_PATIENT = "ParentPatient"; // New in Orthanc 1.12.5 | 3256 static const char* const KEY_PARENT_PATIENT = "ParentPatient"; // New in Orthanc 1.12.5 |
3256 static const char* const KEY_PARENT_STUDY = "ParentStudy"; // New in Orthanc 1.12.5 | 3257 static const char* const KEY_PARENT_STUDY = "ParentStudy"; // New in Orthanc 1.12.5 |
3257 static const char* const KEY_PARENT_SERIES = "ParentSeries"; // New in Orthanc 1.12.5 | 3258 static const char* const KEY_PARENT_SERIES = "ParentSeries"; // New in Orthanc 1.12.5 |
3259 static const char* const KEY_QUERY_METADATA = "QueryMetadata"; // New in Orthanc 1.12.5 | |
3258 | 3260 |
3259 if (call.IsDocumentation()) | 3261 if (call.IsDocumentation()) |
3260 { | 3262 { |
3261 OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human); | 3263 OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human); |
3262 | 3264 |
3294 "Limit the reported resources to descendants of this patient (new in Orthanc 1.12.5)", true) | 3296 "Limit the reported resources to descendants of this patient (new in Orthanc 1.12.5)", true) |
3295 .SetRequestField(KEY_PARENT_STUDY, RestApiCallDocumentation::Type_String, | 3297 .SetRequestField(KEY_PARENT_STUDY, RestApiCallDocumentation::Type_String, |
3296 "Limit the reported resources to descendants of this study (new in Orthanc 1.12.5)", true) | 3298 "Limit the reported resources to descendants of this study (new in Orthanc 1.12.5)", true) |
3297 .SetRequestField(KEY_PARENT_SERIES, RestApiCallDocumentation::Type_String, | 3299 .SetRequestField(KEY_PARENT_SERIES, RestApiCallDocumentation::Type_String, |
3298 "Limit the reported resources to descendants of this series (new in Orthanc 1.12.5)", true) | 3300 "Limit the reported resources to descendants of this series (new in Orthanc 1.12.5)", true) |
3301 .SetRequestField(KEY_QUERY_METADATA, RestApiCallDocumentation::Type_JsonObject, | |
3302 "Associative array containing the filter on the values of the metadata (new in Orthanc 1.12.5)", true) | |
3299 .AddAnswerType(MimeType_Json, "JSON array containing either the Orthanc identifiers, or detailed information " | 3303 .AddAnswerType(MimeType_Json, "JSON array containing either the Orthanc identifiers, or detailed information " |
3300 "about the reported resources (if `Expand` argument is `true`)"); | 3304 "about the reported resources (if `Expand` argument is `true`)"); |
3301 return; | 3305 return; |
3302 } | 3306 } |
3303 | 3307 |
3362 request[KEY_ORDER_BY].type() != Json::arrayValue) | 3366 request[KEY_ORDER_BY].type() != Json::arrayValue) |
3363 { | 3367 { |
3364 throw OrthancException(ErrorCode_BadRequest, | 3368 throw OrthancException(ErrorCode_BadRequest, |
3365 "Field \"" + std::string(KEY_ORDER_BY) + "\" must be an array"); | 3369 "Field \"" + std::string(KEY_ORDER_BY) + "\" must be an array"); |
3366 } | 3370 } |
3371 else if (request.isMember(KEY_QUERY_METADATA) && | |
3372 request[KEY_QUERY_METADATA].type() != Json::objectValue) | |
3373 { | |
3374 throw OrthancException(ErrorCode_BadRequest, | |
3375 "Field \"" + std::string(KEY_QUERY_METADATA) + "\" must be an JSON object"); | |
3376 } | |
3367 else if (request.isMember(KEY_PARENT_PATIENT) && | 3377 else if (request.isMember(KEY_PARENT_PATIENT) && |
3368 request[KEY_PARENT_PATIENT].type() != Json::stringValue) | 3378 request[KEY_PARENT_PATIENT].type() != Json::stringValue) |
3369 { | 3379 { |
3370 throw OrthancException(ErrorCode_BadRequest, | 3380 throw OrthancException(ErrorCode_BadRequest, |
3371 "Field \"" + std::string(KEY_PARENT_PATIENT) + "\" must be a string"); | 3381 "Field \"" + std::string(KEY_PARENT_PATIENT) + "\" must be a string"); |
3434 if (request.isMember(KEY_CASE_SENSITIVE)) | 3444 if (request.isMember(KEY_CASE_SENSITIVE)) |
3435 { | 3445 { |
3436 caseSensitive = request[KEY_CASE_SENSITIVE].asBool(); | 3446 caseSensitive = request[KEY_CASE_SENSITIVE].asBool(); |
3437 } | 3447 } |
3438 | 3448 |
3439 DatabaseLookup query; | 3449 { // DICOM Tag query |
3440 | 3450 DatabaseLookup dicomTagLookup; |
3441 Json::Value::Members members = request[KEY_QUERY].getMemberNames(); | 3451 |
3442 for (size_t i = 0; i < members.size(); i++) | 3452 Json::Value::Members members = request[KEY_QUERY].getMemberNames(); |
3443 { | 3453 for (size_t i = 0; i < members.size(); i++) |
3444 if (request[KEY_QUERY][members[i]].type() != Json::stringValue) | |
3445 { | 3454 { |
3446 throw OrthancException(ErrorCode_BadRequest, | 3455 if (request[KEY_QUERY][members[i]].type() != Json::stringValue) |
3447 "Tag \"" + members[i] + "\" must be associated with a string"); | 3456 { |
3457 throw OrthancException(ErrorCode_BadRequest, | |
3458 "Tag \"" + members[i] + "\" must be associated with a string"); | |
3459 } | |
3460 | |
3461 const std::string value = request[KEY_QUERY][members[i]].asString(); | |
3462 | |
3463 if (!value.empty()) | |
3464 { | |
3465 // An empty string corresponds to an universal constraint, | |
3466 // so we ignore it. This mimics the behavior of class | |
3467 // "OrthancFindRequestHandler" | |
3468 dicomTagLookup.AddRestConstraint(FromDcmtkBridge::ParseTag(members[i]), | |
3469 value, caseSensitive, true); | |
3470 } | |
3448 } | 3471 } |
3449 | 3472 |
3450 const std::string value = request[KEY_QUERY][members[i]].asString(); | 3473 finder.SetDatabaseLookup(dicomTagLookup); |
3451 | 3474 } |
3452 if (!value.empty()) | 3475 |
3476 { // Metadata query | |
3477 Json::Value::Members members = request[KEY_QUERY_METADATA].getMemberNames(); | |
3478 for (size_t i = 0; i < members.size(); i++) | |
3453 { | 3479 { |
3454 // An empty string corresponds to an universal constraint, | 3480 if (request[KEY_QUERY_METADATA][members[i]].type() != Json::stringValue) |
3455 // so we ignore it. This mimics the behavior of class | 3481 { |
3456 // "OrthancFindRequestHandler" | 3482 throw OrthancException(ErrorCode_BadRequest, |
3457 query.AddRestConstraint(FromDcmtkBridge::ParseTag(members[i]), | 3483 "Tag \"" + members[i] + "\" must be associated with a string"); |
3458 value, caseSensitive, true); | 3484 } |
3485 MetadataType metadata = StringToMetadata(members[i]); | |
3486 | |
3487 const std::string value = request[KEY_QUERY_METADATA][members[i]].asString(); | |
3488 | |
3489 if (!value.empty()) | |
3490 { | |
3491 if (value.find('\\') != std::string::npos) | |
3492 { | |
3493 std::vector<std::string> items; | |
3494 Toolbox::TokenizeString(items, value, '\\'); | |
3495 | |
3496 finder.AddMetadataConstraint(new DatabaseMetadataConstraint(metadata, ConstraintType_List, items, caseSensitive)); | |
3497 } | |
3498 else if (value.find('*') != std::string::npos || value.find('?') != std::string::npos) | |
3499 { | |
3500 finder.AddMetadataConstraint(new DatabaseMetadataConstraint(metadata, ConstraintType_Wildcard, value, caseSensitive)); | |
3501 } | |
3502 else | |
3503 { | |
3504 finder.AddMetadataConstraint(new DatabaseMetadataConstraint(metadata, ConstraintType_Equal, value, caseSensitive)); | |
3505 } | |
3506 } | |
3459 } | 3507 } |
3460 } | 3508 } |
3461 | |
3462 finder.SetDatabaseLookup(query); | |
3463 } | 3509 } |
3464 | 3510 |
3465 if (request.isMember(KEY_REQUESTED_TAGS)) | 3511 if (request.isMember(KEY_REQUESTED_TAGS)) |
3466 { | 3512 { |
3467 std::set<DicomTag> requestedTags; | 3513 std::set<DicomTag> requestedTags; |