diff --git a/.doc_gen/metadata/medical-imaging_metadata.yaml b/.doc_gen/metadata/medical-imaging_metadata.yaml index 00049b8ee11..5279ee21b24 100644 --- a/.doc_gen/metadata/medical-imaging_metadata.yaml +++ b/.doc_gen/metadata/medical-imaging_metadata.yaml @@ -394,6 +394,12 @@ medical-imaging_SearchImageSets: previously persisted. snippet_tags: - python.example_code.medical-imaging.SearchImageSets.use_case3 + - description: > + Use case #4: EQUAL operator on DICOMSeriesInstanceUID and + BETWEEN on updatedAt and sort response in ASC order on + updatedAt field. + snippet_tags: + - python.example_code.medical-imaging.SearchImageSets.use_case4 - description: > The following code instantiates the MedicalImagingWrapper object. snippet_tags: @@ -423,6 +429,13 @@ medical-imaging_SearchImageSets: snippet_tags: - medical-imaging.JavaScript.resource.searchImageSetV3.datastoreID - medical-imaging.JavaScript.resource.searchImageSetV3.betweenFilter2 + - description: > + Use case #4: EQUAL operator on DICOMSeriesInstanceUID and + BETWEEN on updatedAt and sort response in ASC order on + updatedAt field. + snippet_tags: + - medical-imaging.JavaScript.resource.searchImageSetV3.datastoreID + - medical-imaging.JavaScript.resource.searchImageSetV3.sortAndFilter Java: versions: - sdk_version: 2 @@ -445,6 +458,12 @@ medical-imaging_SearchImageSets: previously persisted. snippet_tags: - medicalimaging.java2.search_imagesets.use_case3 + - description: > + Use case #4: EQUAL operator on DICOMSeriesInstanceUID and + BETWEEN on updatedAt and sort response in ASC order on + updatedAt field. + snippet_tags: + - medicalimaging.java2.search_imagesets.use_case4 C++: versions: - sdk_version: 1 @@ -467,6 +486,12 @@ medical-imaging_SearchImageSets: previously persisted. snippet_tags: - cpp.example_code.medical_imaging.SearchImageSets.use_case3 + - description: > + Use case #4: EQUAL operator on DICOMSeriesInstanceUID and + BETWEEN on updatedAt and sort response in ASC order on + updatedAt field. + snippet_tags: + - cpp.example_code.medical_imaging.SearchImageSets.use_case4 services: medical-imaging: {SearchImageSets} medical-imaging_GetImageSet: diff --git a/cpp/example_code/medical-imaging/medical-imaging_samples.h b/cpp/example_code/medical-imaging/medical-imaging_samples.h index 3459c6cb027..8e4d6446c17 100644 --- a/cpp/example_code/medical-imaging/medical-imaging_samples.h +++ b/cpp/example_code/medical-imaging/medical-imaging_samples.h @@ -91,11 +91,10 @@ namespace AwsDoc { \param clientConfig: Aws client configuration. \return bool: Function succeeded. */ - bool searchImageSets( - const Aws::String &dataStoreID, - const Aws::MedicalImaging::Model::SearchCriteria &searchCriteria, - Aws::Vector &imageSetResults, - const Aws::Client::ClientConfiguration &clientConfig); + bool searchImageSets(const Aws::String &dataStoreID, + const Aws::MedicalImaging::Model::SearchCriteria &searchCriteria, + Aws::Vector &imageSetResults, + const Aws::Client::ClientConfiguration &clientConfig); } // namespace Medical_Imaging diff --git a/cpp/example_code/medical-imaging/search_image_sets.cpp b/cpp/example_code/medical-imaging/search_image_sets.cpp index 2a17f6d1e19..0db01f25a6a 100644 --- a/cpp/example_code/medical-imaging/search_image_sets.cpp +++ b/cpp/example_code/medical-imaging/search_image_sets.cpp @@ -30,11 +30,10 @@ \param clientConfig: Aws client configuration. \return bool: Function succeeded. */ -bool AwsDoc::Medical_Imaging::searchImageSets( - const Aws::String &dataStoreID, - const Aws::MedicalImaging::Model::SearchCriteria &searchCriteria, - Aws::Vector &imageSetResults, - const Aws::Client::ClientConfiguration &clientConfig) { +bool AwsDoc::Medical_Imaging::searchImageSets(const Aws::String &dataStoreID, + const Aws::MedicalImaging::Model::SearchCriteria &searchCriteria, + Aws::Vector &imageSetResults, + const Aws::Client::ClientConfiguration &clientConfig) { Aws::MedicalImaging::MedicalImagingClient client(clientConfig); Aws::MedicalImaging::Model::SearchImageSetsRequest request; request.SetDatastoreId(dataStoreID); @@ -71,7 +70,7 @@ bool AwsDoc::Medical_Imaging::searchImageSets( * * main function * - * Usage: 'run_search_image_sets ' + * Usage: 'run_search_image_sets ' * * Prerequisites: A HealthImaging data store containing image sets to search. * @@ -80,9 +79,9 @@ bool AwsDoc::Medical_Imaging::searchImageSets( #ifndef TESTING_BUILD int main(int argc, char **argv) { - if (argc != 3) { + if (argc != 4) { std::cout - << "Usage: 'run_search_image_sets '" + << "Usage: 'run_search_image_sets '" << std::endl; return 1; } @@ -91,6 +90,7 @@ int main(int argc, char **argv) { { Aws::String dataStoreID = argv[1]; Aws::String patientID = argv[2]; + Aws::String dicomSeriesInstanceUID = argv[3]; Aws::Client::ClientConfiguration clientConfig; // Optional: Set to the AWS Region in which the bucket was created (overrides config file). @@ -104,8 +104,11 @@ int main(int argc, char **argv) { Aws::MedicalImaging::Model::SearchFilter().WithOperator(Aws::MedicalImaging::Model::Operator::EQUAL) .WithValues({Aws::MedicalImaging::Model::SearchByAttributeValue().WithDICOMPatientId(patientID)}) }; + searchCriteriaEqualsPatientID.SetFilters(patientIDSearchFilters); - bool result = AwsDoc::Medical_Imaging::searchImageSets(dataStoreID, searchCriteriaEqualsPatientID, imageIDsForPatientID, + bool result = AwsDoc::Medical_Imaging::searchImageSets(dataStoreID, + searchCriteriaEqualsPatientID, + imageIDsForPatientID, clientConfig); if (result) { std::cout << imageIDsForPatientID.size() << " image sets found for the patient with ID '" @@ -137,8 +140,10 @@ int main(int argc, char **argv) { useCase2SearchCriteria.SetFilters({useCase2SearchFilter}); Aws::Vector usesCase2Results; - result = AwsDoc::Medical_Imaging::searchImageSets(dataStoreID, useCase2SearchCriteria, usesCase2Results, - clientConfig); + result = AwsDoc::Medical_Imaging::searchImageSets(dataStoreID, + useCase2SearchCriteria, + usesCase2Results, + clientConfig); if (result) { std::cout << usesCase2Results.size() << " image sets found for between 1999/01/01 and present." << std::endl; @@ -165,7 +170,9 @@ int main(int argc, char **argv) { useCase3SearchCriteria.SetFilters({useCase3SearchFilter}); Aws::Vector usesCase3Results; - result = AwsDoc::Medical_Imaging::searchImageSets(dataStoreID, useCase3SearchCriteria, usesCase3Results, + result = AwsDoc::Medical_Imaging::searchImageSets(dataStoreID, + useCase3SearchCriteria, + usesCase3Results, clientConfig); if (result) { std::cout << usesCase3Results.size() << " image sets found for created between 2023/11/30 and present." @@ -176,6 +183,50 @@ int main(int argc, char **argv) { } //snippet-end:[cpp.example_code.medical_imaging.SearchImageSets.use_case3] + // Use case #4: EQUAL operator on DICOMSeriesInstanceUID and BETWEEN on updatedAt and sort response + // in ASC order on updatedAt field. + //snippet-start:[cpp.example_code.medical_imaging.SearchImageSets.use_case4] + Aws::MedicalImaging::Model::SearchByAttributeValue useCase4StartDate; + useCase4StartDate.SetUpdatedAt(Aws::Utils::DateTime("20231130T000000000Z",Aws::Utils::DateFormat::ISO_8601_BASIC)); + + Aws::MedicalImaging::Model::SearchByAttributeValue useCase4EndDate; + useCase4EndDate.SetUpdatedAt(Aws::Utils::DateTime(std::chrono::system_clock::now())); + + Aws::MedicalImaging::Model::SearchFilter useCase4SearchFilterBetween; + useCase4SearchFilterBetween.SetValues({useCase4StartDate, useCase4EndDate}); + useCase4SearchFilterBetween.SetOperator(Aws::MedicalImaging::Model::Operator::BETWEEN); + + Aws::MedicalImaging::Model::SearchByAttributeValue seriesInstanceUID; + seriesInstanceUID.SetDICOMSeriesInstanceUID(dicomSeriesInstanceUID); + + Aws::MedicalImaging::Model::SearchFilter useCase4SearchFilterEqual; + useCase4SearchFilterEqual.SetValues({seriesInstanceUID}); + useCase4SearchFilterEqual.SetOperator(Aws::MedicalImaging::Model::Operator::EQUAL); + + Aws::MedicalImaging::Model::SearchCriteria useCase4SearchCriteria; + useCase4SearchCriteria.SetFilters({useCase4SearchFilterBetween, useCase4SearchFilterEqual}); + + Aws::MedicalImaging::Model::Sort useCase4Sort; + useCase4Sort.SetSortField(Aws::MedicalImaging::Model::SortField::updatedAt); + useCase4Sort.SetSortOrder(Aws::MedicalImaging::Model::SortOrder::ASC); + + useCase4SearchCriteria.SetSort(useCase4Sort); + + Aws::Vector usesCase4Results; + result = AwsDoc::Medical_Imaging::searchImageSets(dataStoreID, + useCase4SearchCriteria, + usesCase4Results, + clientConfig); + if (result) { + std::cout << usesCase4Results.size() << " image sets found for EQUAL operator " + << "on DICOMSeriesInstanceUID and BETWEEN on updatedAt and sort response\n" + << "in ASC order on updatedAt field." << std::endl; + for (auto &imageSetResult : usesCase4Results) { + std::cout << " Image set with ID '" << imageSetResult << std::endl; + } + } + //snippet-end:[cpp.example_code.medical_imaging.SearchImageSets.use_case4] + } Aws::ShutdownAPI(options); diff --git a/javascriptv3/example_code/medical-imaging/actions/search-image-sets.js b/javascriptv3/example_code/medical-imaging/actions/search-image-sets.js index 0b9c8049fae..4f66bd10c49 100644 --- a/javascriptv3/example_code/medical-imaging/actions/search-image-sets.js +++ b/javascriptv3/example_code/medical-imaging/actions/search-image-sets.js @@ -1,129 +1,167 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fileURLToPath } from "url"; +import {fileURLToPath} from "url"; // snippet-start:[medical-imaging.JavaScript.resource.searchImageSetV3] -import { paginateSearchImageSets } from "@aws-sdk/client-medical-imaging"; -import { medicalImagingClient } from "../libs/medicalImagingClient.js"; +import {paginateSearchImageSets} from "@aws-sdk/client-medical-imaging"; +import {medicalImagingClient} from "../libs/medicalImagingClient.js"; /** * @param {string} datastoreId - The data store's ID. * @param { import('@aws-sdk/client-medical-imaging').SearchFilter[] } filters - The search criteria filters. + * @param { import('@aws-sdk/client-medical-imaging').Sort } sort - The search criteria sort. */ export const searchImageSets = async ( - datastoreId = "xxxxxxxx", - filters = [] + datastoreId = "xxxxxxxx", + searchCriteria = {} ) => { - const paginatorConfig = { - client: medicalImagingClient, - pageSize: 50, - }; - - const commandParams = { - datastoreId: datastoreId, - searchCriteria: { - filters, - }, - }; - - const paginator = paginateSearchImageSets(paginatorConfig, commandParams); - - const imageSetsMetadataSummaries = []; - for await (const page of paginator) { - // Each page contains a list of `jobSummaries`. The list is truncated if is larger than `pageSize`. - imageSetsMetadataSummaries.push(...page["imageSetsMetadataSummaries"]); - console.log(page); - } - // { - // '$metadata': { - // httpStatusCode: 200, - // requestId: 'f009ea9c-84ca-4749-b5b6-7164f00a5ada', - // extendedRequestId: undefined, - // cfId: undefined, - // attempts: 1, - // totalRetryDelay: 0 - // }, - // imageSetsMetadataSummaries: [ - // { - // DICOMTags: [Object], - // createdAt: "2023-09-19T16:59:40.551Z", - // imageSetId: '7f75e1b5c0f40eac2b24cf712f485f50', - // updatedAt: "2023-09-19T16:59:40.551Z", - // version: 1 - // }] - // } - - return imageSetsMetadataSummaries; + const paginatorConfig = { + client: medicalImagingClient, + pageSize: 50, + }; + + const commandParams = { + datastoreId: datastoreId, + searchCriteria: searchCriteria, + }; + + const paginator = paginateSearchImageSets(paginatorConfig, commandParams); + + const imageSetsMetadataSummaries = []; + for await (const page of paginator) { + // Each page contains a list of `jobSummaries`. The list is truncated if is larger than `pageSize`. + imageSetsMetadataSummaries.push(...page["imageSetsMetadataSummaries"]); + console.log(page); + } + // { + // '$metadata': { + // httpStatusCode: 200, + // requestId: 'f009ea9c-84ca-4749-b5b6-7164f00a5ada', + // extendedRequestId: undefined, + // cfId: undefined, + // attempts: 1, + // totalRetryDelay: 0 + // }, + // imageSetsMetadataSummaries: [ + // { + // DICOMTags: [Object], + // createdAt: "2023-09-19T16:59:40.551Z", + // imageSetId: '7f75e1b5c0f40eac2b24cf712f485f50', + // updatedAt: "2023-09-19T16:59:40.551Z", + // version: 1 + // }] + // } + + return imageSetsMetadataSummaries; }; // snippet-end:[medical-imaging.JavaScript.resource.searchImageSetV3] // Invoke the following code if this file is being run directly. if (process.argv[1] === fileURLToPath(import.meta.url)) { - // snippet-start:[medical-imaging.JavaScript.resource.searchImageSetV3.datastoreID] - const datastoreId = "12345678901234567890123456789012"; - // snippet-end:[medical-imaging.JavaScript.resource.searchImageSetV3.datastoreID] - // Search using EQUAL operator. - // snippet-start:[medical-imaging.JavaScript.resource.searchImageSetV3.equalFilter] - try { - const filters = [ - { - values: [{ DICOMPatientId: "9227465" }], - operator: "EQUAL", - }, - ]; - - await searchImageSets(datastoreId, filters); - } catch (err) { - console.error(err); - } - // snippet-end:[medical-imaging.JavaScript.resource.searchImageSetV3.equalFilter] - - // Search with BETWEEN operator using DICOMStudyDate and DICOMStudyTime. - // snippet-start:[medical-imaging.JavaScript.resource.searchImageSetV3.betweenFilter1] - try { - const filters = [ - { - values: [ - { - DICOMStudyDateAndTime: { - DICOMStudyDate: "19900101", - DICOMStudyTime: "000000", - }, - }, - { - DICOMStudyDateAndTime: { - DICOMStudyDate: "20230901", - DICOMStudyTime: "000000", - }, - }, - ], - operator: "BETWEEN", - }, - ]; - - await searchImageSets(datastoreId, filters); - } catch (err) { - console.error(err); - } - // snippet-end:[medical-imaging.JavaScript.resource.searchImageSetV3.betweenFilter1] - - // Search with BETWEEN operator and createdAt date. - // snippet-start:[medical-imaging.JavaScript.resource.searchImageSetV3.betweenFilter2] - try { - const filters = [ - { - values: [ - { createdAt: new Date("1985-04-12T23:20:50.52Z") }, - { createdAt: new Date("2023-09-12T23:20:50.52Z") }, - ], - operator: "BETWEEN", - }, - ]; - - await searchImageSets(datastoreId, filters); - } catch (err) { - console.error(err); - } - // snippet-end:[medical-imaging.JavaScript.resource.searchImageSetV3.betweenFilter2] + // snippet-start:[medical-imaging.JavaScript.resource.searchImageSetV3.datastoreID] + const datastoreId = "12345678901234567890123456789012"; + // snippet-end:[medical-imaging.JavaScript.resource.searchImageSetV3.datastoreID] + // Search using EQUAL operator. + // snippet-start:[medical-imaging.JavaScript.resource.searchImageSetV3.equalFilter] + try { + const searchCriteria = { + filters: [ + { + values: [{DICOMPatientId: "1234567"}], + operator: "EQUAL", + }, + ] + }; + + await searchImageSets(datastoreId, searchCriteria); + } catch (err) { + console.error(err); + } + // snippet-end:[medical-imaging.JavaScript.resource.searchImageSetV3.equalFilter] + + // Search with BETWEEN operator using DICOMStudyDate and DICOMStudyTime. + // snippet-start:[medical-imaging.JavaScript.resource.searchImageSetV3.betweenFilter1] + try { + const searchCriteria = { + filters: [ + { + values: [ + { + DICOMStudyDateAndTime: { + DICOMStudyDate: "19900101", + DICOMStudyTime: "000000", + }, + }, + { + DICOMStudyDateAndTime: { + DICOMStudyDate: "20230901", + DICOMStudyTime: "000000", + }, + }, + ], + operator: "BETWEEN", + }, + ] + }; + + await searchImageSets(datastoreId, searchCriteria); + } catch (err) { + console.error(err); + } + // snippet-end:[medical-imaging.JavaScript.resource.searchImageSetV3.betweenFilter1] + + // Search with BETWEEN operator and createdAt date. + // snippet-start:[medical-imaging.JavaScript.resource.searchImageSetV3.betweenFilter2] + try { + const searchCriteria = { + filters: [ + { + values: [ + {createdAt: new Date("1985-04-12T23:20:50.52Z")}, + {createdAt: new Date()}, + ], + operator: "BETWEEN", + }, + ] + }; + + await searchImageSets(datastoreId, searchCriteria); + } catch (err) { + console.error(err); + } + // snippet-end:[medical-imaging.JavaScript.resource.searchImageSetV3.betweenFilter2] + + // Search with EQUAL operator on DICOMSeriesInstanceUID and BETWEEN on updatedAt and sort response in ASC + // order on updatedAt field. + // snippet-start:[medical-imaging.JavaScript.resource.searchImageSetV3.sortAndFilter] + try { + const searchCriteria = { + filters: [ + { + values: [ + {updatedAt: new Date("1985-04-12T23:20:50.52Z")}, + {updatedAt: new Date()}, + ], + operator: "BETWEEN", + }, + { + values: [ + {DICOMSeriesInstanceUID: "1.1.123.123456.1.12.1.1234567890.1234.12345678.123"}, + ], + operator: "EQUAL", + }, + ], + sort: { + sortOrder: "ASC", + sortField: "updatedAt", + } + }; + + await searchImageSets(datastoreId, searchCriteria); + } catch (err) { + console.error(err); + } + // snippet-end:[medical-imaging.JavaScript.resource.searchImageSetV3.sortAndFilter] + } diff --git a/javascriptv3/example_code/medical-imaging/tests/search-image-set.unit.test.js b/javascriptv3/example_code/medical-imaging/tests/search-image-set.unit.test.js index f380e3e0846..e125cfba14d 100644 --- a/javascriptv3/example_code/medical-imaging/tests/search-image-set.unit.test.js +++ b/javascriptv3/example_code/medical-imaging/tests/search-image-set.unit.test.js @@ -1,61 +1,63 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { describe, it, expect, vi } from "vitest"; +import {describe, it, expect, vi} from "vitest"; const paginateSearchImageSets = vi.fn(); vi.doMock("@aws-sdk/client-medical-imaging", async () => { - const actual = await vi.importActual("@aws-sdk/client-medical-imaging"); + const actual = await vi.importActual("@aws-sdk/client-medical-imaging"); - return { - ...actual, - paginateSearchImageSets, - }; + return { + ...actual, + paginateSearchImageSets, + }; }); -const { searchImageSets } = await import("../actions/search-image-sets.js"); +const {searchImageSets} = await import("../actions/search-image-sets.js"); describe("search-image-sets", () => { - it("should log the response", async () => { - const logSpy = vi.spyOn(console, "log"); - const datastoreId = "12345678901234567890123456789012"; - const filters = [ - { - values: [ - { createdAt: new Date("1985-04-12T23:20:50.52Z") }, - { createdAt: new Date("2023-09-12T23:20:50.52Z") }, - ], - operator: "BETWEEN", - }, - ]; - - const response = { - $metadata: { - httpStatusCode: 200, - requestId: "f009ea9c-84ca-4749-b5b6-7164f00a5ada", - extendedRequestId: undefined, - cfId: undefined, - attempts: 1, - totalRetryDelay: 0, - }, - imageSetsMetadataSummaries: [ - { - DICOMTags: [Object], - createdAt: "2023-09-19T16:59:40.551Z", - imageSetId: "7f75e1b5c0f40eac2b24cf712f485f50", - updatedAt: "2023-09-19T16:59:40.551Z", - version: 1, - }, - ], - }; - - paginateSearchImageSets.mockImplementationOnce(async function* () { - yield response; + it("should log the response", async () => { + const logSpy = vi.spyOn(console, "log"); + const datastoreId = "12345678901234567890123456789012"; + const searchCriteria = { + filters: [ + { + values: [ + {createdAt: new Date("1985-04-12T23:20:50.52Z")}, + {createdAt: new Date()}, + ], + operator: "BETWEEN", + }, + ] + }; + + const response = { + $metadata: { + httpStatusCode: 200, + requestId: "f009ea9c-84ca-4749-b5b6-7164f00a5ada", + extendedRequestId: undefined, + cfId: undefined, + attempts: 1, + totalRetryDelay: 0, + }, + imageSetsMetadataSummaries: [ + { + DICOMTags: [Object], + createdAt: "2023-09-19T16:59:40.551Z", + imageSetId: "7f75e1b5c0f40eac2b24cf712f485f50", + updatedAt: "2023-09-19T16:59:40.551Z", + version: 1, + }, + ], + }; + + paginateSearchImageSets.mockImplementationOnce(async function* () { + yield response; + }); + + await searchImageSets(datastoreId, searchCriteria); + + expect(logSpy).toHaveBeenCalledWith(response); }); - - await searchImageSets(datastoreId, filters); - - expect(logSpy).toHaveBeenCalledWith(response); - }); }); diff --git a/javav2/example_code/medicalimaging/README.md b/javav2/example_code/medicalimaging/README.md index 855e90bfee5..91096f6dcc4 100644 --- a/javav2/example_code/medicalimaging/README.md +++ b/javav2/example_code/medicalimaging/README.md @@ -49,7 +49,7 @@ Code excerpts that show you how to call individual service functions. - [List import jobs for a data store](src/main/java/com/example/medicalimaging/ListDicomImportJobs.java#L58) (`ListDICOMImportJobs`) - [List tags for a resource](src/main/java/com/example/medicalimaging/ListTagsForResource.java#L56) (`ListTagsForResource`) - [Remove a tag from a resource](src/main/java/com/example/medicalimaging/UntagResource.java#L54) (`UntagResource`) -- [Search image sets](src/main/java/com/example/medicalimaging/SearchImageSets.java#L130) (`SearchImageSets`) +- [Search image sets](src/main/java/com/example/medicalimaging/SearchImageSets.java#L182) (`SearchImageSets`) - [Update image set metadata](src/main/java/com/example/medicalimaging/UpdateImageSetMetadata.java#L144) (`UpdateImageSetMetadata`) ### Scenarios diff --git a/javav2/example_code/medicalimaging/pom.xml b/javav2/example_code/medicalimaging/pom.xml index 6168ca7f3c4..bf1a283a6e0 100644 --- a/javav2/example_code/medicalimaging/pom.xml +++ b/javav2/example_code/medicalimaging/pom.xml @@ -8,8 +8,8 @@ 1.0-SNAPSHOT UTF-8 - 17 - 2.20.132 + 1.8 + 2.25.25 diff --git a/javav2/example_code/medicalimaging/src/main/java/com/example/medicalimaging/SearchImageSets.java b/javav2/example_code/medicalimaging/src/main/java/com/example/medicalimaging/SearchImageSets.java index 76f003629e6..f5e88eb4a03 100644 --- a/javav2/example_code/medicalimaging/src/main/java/com/example/medicalimaging/SearchImageSets.java +++ b/javav2/example_code/medicalimaging/src/main/java/com/example/medicalimaging/SearchImageSets.java @@ -15,6 +15,7 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; // snippet-end:[medicalimaging.java2.search_imagesets.import] @@ -30,126 +31,177 @@ public class SearchImageSets { - public static void main(String[] args) { - final String usage = "\n" + - "Usage:\n" + - " \n\n" + - "Where:\n" + - " datastoreId - The ID of the data store.\n" + - " patientId - The ID of the patient to search for.\\n"; - - if (args.length != 2) { - System.out.println(usage); - System.exit(1); - } - - String datastoreId = args[0]; - String patientId = args[1]; - - Region region = Region.US_WEST_2; - MedicalImagingClient medicalImagingClient = MedicalImagingClient.builder() - .region(region) - .credentialsProvider(ProfileCredentialsProvider.create()) - .build(); - - // Use case #1: EQUAL operator. - // snippet-start:[medicalimaging.java2.search_imagesets.use_case1] - List searchFilters = Collections.singletonList(SearchFilter.builder() - .operator(Operator.EQUAL) - .values(SearchByAttributeValue.builder() - .dicomPatientId(patientId) - .build()) - .build()); - - List imageSetsMetadataSummaries = searchMedicalImagingImageSets( - medicalImagingClient, - datastoreId, searchFilters); - if (imageSetsMetadataSummaries != null) { - System.out.println("The image sets for patient " + patientId + " are:\n" - + imageSetsMetadataSummaries); - System.out.println(); - } - // snippet-end:[medicalimaging.java2.search_imagesets.use_case1] - - // Use case #2: BETWEEN operator using DICOMStudyDate and DICOMStudyTime. - // snippet-start:[medicalimaging.java2.search_imagesets.use_case2] - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); - searchFilters = Collections.singletonList(SearchFilter.builder() - .operator(Operator.BETWEEN) - .values(SearchByAttributeValue.builder() - .dicomStudyDateAndTime(DICOMStudyDateAndTime.builder() - .dicomStudyDate("19990101") - .dicomStudyTime("000000.000") - .build()) - .build(), - SearchByAttributeValue.builder() - .dicomStudyDateAndTime(DICOMStudyDateAndTime.builder() - .dicomStudyDate((LocalDate.now() - .format(formatter))) - .dicomStudyTime("000000.000") - .build()) - .build()) - .build()); - - imageSetsMetadataSummaries = searchMedicalImagingImageSets(medicalImagingClient, - datastoreId, searchFilters); - if (imageSetsMetadataSummaries != null) { - System.out.println( - "The image sets searched with BETWEEN operator using DICOMStudyDate and DICOMStudyTime are:\n" - + - imageSetsMetadataSummaries); - System.out.println(); - } - // snippet-end:[medicalimaging.java2.search_imagesets.use_case2] - - // Use case #3: BETWEEN operator using createdAt. Time studies were previously - // persisted. - // snippet-start:[medicalimaging.java2.search_imagesets.use_case3] - searchFilters = Collections.singletonList(SearchFilter.builder() - .operator(Operator.BETWEEN) - .values(SearchByAttributeValue.builder() - .createdAt(Instant.parse("1985-04-12T23:20:50.52Z")) - .build(), - SearchByAttributeValue.builder() - .createdAt(Instant.now()) - .build()) - .build()); - - imageSetsMetadataSummaries = searchMedicalImagingImageSets(medicalImagingClient, - datastoreId, searchFilters); - if (imageSetsMetadataSummaries != null) { - System.out.println("The image sets searched with BETWEEN operator using createdAt are:\n " - + imageSetsMetadataSummaries); - System.out.println(); - } - // snippet-end:[medicalimaging.java2.search_imagesets.use_case3] - - medicalImagingClient.close(); + public static void main(String[] args) { + final String usage = "\n" + + "Usage:\n" + + " \n\n" + + "Where:\n" + + " datastoreId - The ID of the data store.\n" + + " patientId - The ID of the patient to search for.\n" + + " seriesInstanceUID - The ID of the series instance to search for.\\n"; + + + if (args.length != 3) { + System.out.println(usage); + System.exit(1); } - // snippet-start:[medicalimaging.java2.search_imagesets.main] - public static List searchMedicalImagingImageSets( - MedicalImagingClient medicalImagingClient, - String datastoreId, List searchFilters) { - try { - SearchImageSetsRequest datastoreRequest = SearchImageSetsRequest.builder() - .datastoreId(datastoreId) - .searchCriteria(SearchCriteria.builder().filters(searchFilters).build()) - .build(); - SearchImageSetsIterable responses = medicalImagingClient - .searchImageSetsPaginator(datastoreRequest); - List imageSetsMetadataSummaries = new ArrayList<>(); - - responses.stream().forEach(response -> imageSetsMetadataSummaries - .addAll(response.imageSetsMetadataSummaries())); - - return imageSetsMetadataSummaries; - } catch (MedicalImagingException e) { - System.err.println(e.awsErrorDetails().errorMessage()); - System.exit(1); - } - - return null; + String datastoreId = args[0]; + String patientId = args[1]; + String seriesInstanceUID = args[2]; + + Region region = Region.US_EAST_1; + MedicalImagingClient medicalImagingClient = MedicalImagingClient.builder() + .region(region) + .credentialsProvider(ProfileCredentialsProvider.create()) + .build(); + + // Use case #1: EQUAL operator. + // snippet-start:[medicalimaging.java2.search_imagesets.use_case1] + List searchFilters = Collections.singletonList(SearchFilter.builder() + .operator(Operator.EQUAL) + .values(SearchByAttributeValue.builder() + .dicomPatientId(patientId) + .build()) + .build()); + + SearchCriteria searchCriteria = SearchCriteria.builder() + .filters(searchFilters) + .build(); + + List imageSetsMetadataSummaries = searchMedicalImagingImageSets( + medicalImagingClient, + datastoreId, searchCriteria); + if (imageSetsMetadataSummaries != null) { + System.out.println("The image sets for patient " + patientId + " are:\n" + + imageSetsMetadataSummaries); + System.out.println(); + } + // snippet-end:[medicalimaging.java2.search_imagesets.use_case1] + + // Use case #2: BETWEEN operator using DICOMStudyDate and DICOMStudyTime. + // snippet-start:[medicalimaging.java2.search_imagesets.use_case2] + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); + searchFilters = Collections.singletonList(SearchFilter.builder() + .operator(Operator.BETWEEN) + .values(SearchByAttributeValue.builder() + .dicomStudyDateAndTime(DICOMStudyDateAndTime.builder() + .dicomStudyDate("19990101") + .dicomStudyTime("000000.000") + .build()) + .build(), + SearchByAttributeValue.builder() + .dicomStudyDateAndTime(DICOMStudyDateAndTime.builder() + .dicomStudyDate((LocalDate.now() + .format(formatter))) + .dicomStudyTime("000000.000") + .build()) + .build()) + .build()); + + searchCriteria = SearchCriteria.builder() + .filters(searchFilters) + .build(); + + imageSetsMetadataSummaries = searchMedicalImagingImageSets(medicalImagingClient, + datastoreId, searchCriteria); + if (imageSetsMetadataSummaries != null) { + System.out.println( + "The image sets searched with BETWEEN operator using DICOMStudyDate and DICOMStudyTime are:\n" + + + imageSetsMetadataSummaries); + System.out.println(); + } + // snippet-end:[medicalimaging.java2.search_imagesets.use_case2] + + // Use case #3: BETWEEN operator using createdAt. Time studies were previously + // persisted. + // snippet-start:[medicalimaging.java2.search_imagesets.use_case3] + searchFilters = Collections.singletonList(SearchFilter.builder() + .operator(Operator.BETWEEN) + .values(SearchByAttributeValue.builder() + .createdAt(Instant.parse("1985-04-12T23:20:50.52Z")) + .build(), + SearchByAttributeValue.builder() + .createdAt(Instant.now()) + .build()) + .build()); + + searchCriteria = SearchCriteria.builder() + .filters(searchFilters) + .build(); + imageSetsMetadataSummaries = searchMedicalImagingImageSets(medicalImagingClient, + datastoreId, searchCriteria); + if (imageSetsMetadataSummaries != null) { + System.out.println("The image sets searched with BETWEEN operator using createdAt are:\n " + + imageSetsMetadataSummaries); + System.out.println(); } - // snippet-end:[medicalimaging.java2.search_imagesets.main] + // snippet-end:[medicalimaging.java2.search_imagesets.use_case3] + + // Use case #4: EQUAL operator on DICOMSeriesInstanceUID and BETWEEN on updatedAt and sort response + // in ASC order on updatedAt field. + // snippet-start:[medicalimaging.java2.search_imagesets.use_case4] + Instant startDate = Instant.parse("1985-04-12T23:20:50.52Z"); + Instant endDate = Instant.now(); + + searchFilters = Arrays.asList( + SearchFilter.builder() + .operator(Operator.EQUAL) + .values(SearchByAttributeValue.builder() + .dicomSeriesInstanceUID(seriesInstanceUID) + .build()) + .build(), + SearchFilter.builder() + .operator(Operator.BETWEEN) + .values( + SearchByAttributeValue.builder().updatedAt(startDate).build(), + SearchByAttributeValue.builder().updatedAt(endDate).build() + ).build()); + + Sort sort = Sort.builder().sortOrder(SortOrder.ASC).sortField(SortField.UPDATED_AT).build(); + + searchCriteria = SearchCriteria.builder() + .filters(searchFilters) + .sort(sort) + .build(); + + imageSetsMetadataSummaries = searchMedicalImagingImageSets(medicalImagingClient, + datastoreId, searchCriteria); + if (imageSetsMetadataSummaries != null) { + System.out.println("The image sets searched with EQUAL operator on DICOMSeriesInstanceUID and BETWEEN on updatedAt and sort response\n" + + "in ASC order on updatedAt field are:\n " + + imageSetsMetadataSummaries); + System.out.println(); + } + // snippet-end:[medicalimaging.java2.search_imagesets.use_case4] + + medicalImagingClient.close(); + } + + // snippet-start:[medicalimaging.java2.search_imagesets.main] + public static List searchMedicalImagingImageSets( + MedicalImagingClient medicalImagingClient, + String datastoreId, SearchCriteria searchCriteria) { + try { + SearchImageSetsRequest datastoreRequest = SearchImageSetsRequest.builder() + .datastoreId(datastoreId) + .searchCriteria(searchCriteria) + .build(); + SearchImageSetsIterable responses = medicalImagingClient + .searchImageSetsPaginator(datastoreRequest); + List imageSetsMetadataSummaries = new ArrayList<>(); + + responses.stream().forEach(response -> imageSetsMetadataSummaries + .addAll(response.imageSetsMetadataSummaries())); + + return imageSetsMetadataSummaries; + } catch (MedicalImagingException e) { + System.err.println(e.awsErrorDetails().errorMessage()); + System.exit(1); + } + + return null; + } + // snippet-end:[medicalimaging.java2.search_imagesets.main] } diff --git a/python/example_code/medical-imaging/medical_imaging_basics.py b/python/example_code/medical-imaging/medical_imaging_basics.py index e4f57820dd1..1555bc81f9a 100644 --- a/python/example_code/medical-imaging/medical_imaging_basics.py +++ b/python/example_code/medical-imaging/medical_imaging_basics.py @@ -554,60 +554,25 @@ def list_tags_for_resource(self, resource_arn): # snippet-end:[python.example_code.medical-imaging.ListTagsForResource] - def usage_demo(self, source_s3_uri, dest_s3_uri, data_access_role_arn): - data_store_name = f"python_usage_demo_data_store_{random.randint(0, 200000)}" - - data_store_id = self.create_datastore(data_store_name) - print(f"Data store created with id : {data_store_id}") - - while True: - time.sleep(1) - datastore_properties = self.get_datastore_properties(data_store_id) - datastore_status = datastore_properties["datastoreStatus"] - print(f'data store status: "{datastore_status}"') - if datastore_status == "ACTIVE": - break - elif datastore_status == "CREATE_FAILED": - raise Exception("Create datastore job failed") - - datastores = self.list_datastores() - print(f"datastores : {datastores}") - - job_name = "python_usage_demo_job" - job_id = self.start_dicom_import_job( - job_name, data_store_id, data_access_role_arn, source_s3_uri, dest_s3_uri - ) - print(f"Started import job with id: {job_id}") - - while True: - time.sleep(1) - job = self.get_dicom_import_job(data_store_id, job_id) - job_status = job["jobStatus"] - print(f'Status of import job : "{job_status}"') - if job_status == "COMPLETED": - break - elif job_status == "FAILED": - raise Exception("DICOM import job failed") - - import_jobs = self.list_dicom_import_jobs(data_store_id) - print(import_jobs) - for job in import_jobs: - print(job) - - # Search with EQUAL operator.. - # snippet-start:[python.example_code.medical-imaging.SearchImageSets.use_case1] - filter = { + def search_imagesets_demo(self, data_store_id): + # Replace these values with your own. + patient_id = "123456" + series_instance_uid = "1.1.123.123456.1.12.1.1234567890.1234.12345678.123" + # Search with EQUAL operator. + # snippet-start:[python.example_code.medical-imaging.SearchImageSets.use_case1] + search_filter = { "filters": [ - {"operator": "EQUAL", "values": [{"DICOMPatientId": "3524578"}]} + {"operator": "EQUAL", "values": [{"DICOMPatientId": patient_id}]} ] } - image_sets = self.search_image_sets(data_store_id, filter) + image_sets = self.search_image_sets(data_store_id, search_filter) + print(f"Image sets found with EQUAL operator\n{image_sets}") # snippet-end:[python.example_code.medical-imaging.SearchImageSets.use_case1] # Search with BETWEEN operator using DICOMStudyDate and DICOMStudyTime. # snippet-start:[python.example_code.medical-imaging.SearchImageSets.use_case2] - filter = { + search_filter = { "filters": [ { "operator": "BETWEEN", @@ -629,12 +594,15 @@ def usage_demo(self, source_s3_uri, dest_s3_uri, data_access_role_arn): ] } - image_sets = self.search_image_sets(data_store_id, filter) + image_sets = self.search_image_sets(data_store_id, search_filter) + print( + f"Image sets found with BETWEEN operator using DICOMStudyDate and DICOMStudyTime\n{image_sets}" + ) # snippet-end:[python.example_code.medical-imaging.SearchImageSets.use_case2] # Search with BETWEEN operator using createdAt. Time studies were previously persisted. # snippet-start:[python.example_code.medical-imaging.SearchImageSets.use_case3] - filter = { + search_filter = { "filters": [ { "values": [ @@ -653,9 +621,93 @@ def usage_demo(self, source_s3_uri, dest_s3_uri, data_access_role_arn): ] } - image_sets = self.search_image_sets(data_store_id, filter) + recent_image_sets = self.search_image_sets(data_store_id, search_filter) + print( + f"Image sets found with with BETWEEN operator using createdAt\n{recent_image_sets}" + ) # snippet-end:[python.example_code.medical-imaging.SearchImageSets.use_case3] + # Search with EQUAL operator on DICOMSeriesInstanceUID and BETWEEN on updatedAt and sort response in ASC + # order on updatedAt field. + # snippet-start:[python.example_code.medical-imaging.SearchImageSets.use_case4] + search_filter = { + "filters": [ + { + "values": [ + { + "updatedAt": datetime.datetime( + 2021, 8, 4, 14, 49, 54, 429000 + ) + }, + { + "updatedAt": datetime.datetime.now() + + datetime.timedelta(days=1) + }, + ], + "operator": "BETWEEN", + }, + { + "values": [{"DICOMSeriesInstanceUID": series_instance_uid}], + "operator": "EQUAL", + }, + ], + "sort": { + "sortOrder": "ASC", + "sortField": "updatedAt", + }, + } + + image_sets = self.search_image_sets(data_store_id, search_filter) + print( + "Image sets found with EQUAL operator on DICOMSeriesInstanceUID and BETWEEN on updatedAt and" + ) + print(f"sort response in ASC order on updatedAt field\n{image_sets}") + # snippet-end:[python.example_code.medical-imaging.SearchImageSets.use_case4] + + return recent_image_sets + + def usage_demo(self, source_s3_uri, dest_s3_uri, data_access_role_arn): + data_store_name = f"python_usage_demo_data_store_{random.randint(0, 200000)}" + + data_store_id = self.create_datastore(data_store_name) + print(f"Data store created with id : {data_store_id}") + + while True: + time.sleep(1) + datastore_properties = self.get_datastore_properties(data_store_id) + datastore_status = datastore_properties["datastoreStatus"] + print(f'data store status: "{datastore_status}"') + if datastore_status == "ACTIVE": + break + elif datastore_status == "CREATE_FAILED": + raise Exception("Create datastore job failed") + + datastores = self.list_datastores() + print(f"datastores : {datastores}") + + job_name = "python_usage_demo_job" + job_id = self.start_dicom_import_job( + job_name, data_store_id, data_access_role_arn, source_s3_uri, dest_s3_uri + ) + print(f"Started import job with id: {job_id}") + + while True: + time.sleep(1) + job = self.get_dicom_import_job(data_store_id, job_id) + job_status = job["jobStatus"] + print(f'Status of import job : "{job_status}"') + if job_status == "COMPLETED": + break + elif job_status == "FAILED": + raise Exception("DICOM import job failed") + + import_jobs = self.list_dicom_import_jobs(data_store_id) + print(import_jobs) + for job in import_jobs: + print(job) + + image_sets = self.search_imagesets_demo(data_store_id) + image_set_ids = [image_set["imageSetId"] for image_set in image_sets] for image_set in image_sets: print(image_set) diff --git a/python/example_code/medical-imaging/requirements.txt b/python/example_code/medical-imaging/requirements.txt index 6a14b87b4d1..3ef6d7037a9 100644 --- a/python/example_code/medical-imaging/requirements.txt +++ b/python/example_code/medical-imaging/requirements.txt @@ -1,5 +1,5 @@ -boto3>=1.26.79 +boto3>=1.34.78 pytest>=7.2.1 requests>=2.28.2 openjphpy>=0.1.0 -botocore~=1.31.30 \ No newline at end of file +botocore>=1.34.78 \ No newline at end of file