From a0877d81ca2844d75dc361b5ce7c99afacd6e25f Mon Sep 17 00:00:00 2001 From: vlad Date: Thu, 25 Jan 2018 14:12:31 -0800 Subject: Extracting query library --- src/main/scala/xyz/driver/pdsuicommon/Config.scala | 21 - .../scala/xyz/driver/pdsuicommon/acl/ACL.scala | 280 ------------ .../xyz/driver/pdsuicommon/compat/EitherOps.scala | 14 - .../xyz/driver/pdsuicommon/compat/Implicits.scala | 7 - .../pdsuicommon/computation/Computation.scala | 124 ------ .../pdsuicommon/concurrent/BridgeUploadQueue.scala | 84 ---- .../xyz/driver/pdsuicommon/concurrent/Cron.scala | 93 ---- .../concurrent/InMemoryBridgeUploadQueue.scala | 37 -- .../concurrent/MdcExecutionContext.scala | 35 -- .../pdsuicommon/concurrent/MdcThreadFactory.scala | 33 -- .../concurrent/SafeBridgeUploadQueue.scala | 60 --- .../scala/xyz/driver/pdsuicommon/db/DbIo.scala | 13 - .../pdsuicommon/db/EntityNotFoundException.scala | 10 - .../scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala | 28 -- .../xyz/driver/pdsuicommon/db/Pagination.scala | 19 - .../driver/pdsuicommon/db/SearchFilterExpr.scala | 208 --------- .../pdsuicommon/db/SlickPostgresQueryBuilder.scala | 115 ----- .../driver/pdsuicommon/db/SlickQueryBuilder.scala | 387 ---------------- .../scala/xyz/driver/pdsuicommon/db/Sorting.scala | 61 --- .../pdsuicommon/db/TransactionalContext.scala | 11 - .../pdsuicommon/db/repositories/Repository.scala | 3 - .../db/repositories/RepositoryLogging.scala | 62 --- .../scala/xyz/driver/pdsuicommon/domain/Id.scala | 51 --- .../xyz/driver/pdsuicommon/domain/TextJson.scala | 14 - .../xyz/driver/pdsuicommon/error/DomainError.scala | 27 -- .../xyz/driver/pdsuicommon/error/ErrorCode.scala | 20 - .../driver/pdsuicommon/error/ErrorsResponse.scala | 52 --- .../pdsuicommon/error/ExceptionFormatter.scala | 18 - .../error/FailedValidationException.scala | 5 - .../pdsuicommon/error/IncorrectIdException.scala | 3 - .../pdsuicommon/http/AsyncHttpClientFetcher.scala | 90 ---- .../pdsuicommon/http/AsyncHttpClientUploader.scala | 115 ----- .../xyz/driver/pdsuicommon/http/Directives.scala | 114 ----- .../xyz/driver/pdsuicommon/http/package.scala | 9 - .../driver/pdsuicommon/json/JsonSerializer.scala | 27 -- .../pdsuicommon/logging/DefaultPhiLogger.scala | 17 - .../xyz/driver/pdsuicommon/logging/Implicits.scala | 62 --- .../xyz/driver/pdsuicommon/logging/PhiLogger.scala | 15 - .../driver/pdsuicommon/logging/PhiLogging.scala | 20 - .../xyz/driver/pdsuicommon/logging/PhiString.scala | 6 - .../pdsuicommon/logging/PhiStringContext.scala | 8 - .../driver/pdsuicommon/logging/TimeLogger.scala | 13 - .../xyz/driver/pdsuicommon/logging/Unsafe.scala | 7 - .../xyz/driver/pdsuicommon/logging/package.scala | 3 - .../pdsuicommon/parsers/DimensionsParser.scala | 30 -- .../pdsuicommon/parsers/PaginationParser.scala | 29 -- .../parsers/ParseQueryArgException.scala | 3 - .../pdsuicommon/parsers/SearchFilterParser.scala | 178 -------- .../driver/pdsuicommon/parsers/SortingParser.scala | 64 --- .../pdsuicommon/serialization/Marshaller.scala | 6 - .../synchronization/db/SlickDataSource.scala | 23 - .../synchronization/db/SlickDbAction.scala | 70 --- .../synchronization/db/SlickDbDiff.scala | 52 --- .../synchronization/domain/FakeId.scala | 14 - .../synchronization/utils/FakeIdGen.scala | 26 -- .../synchronization/utils/Refiner.scala | 12 - .../synchronization/utils/package.scala | 64 --- .../xyz/driver/pdsuicommon/utils/CharOps.scala | 31 -- .../utils/CustomSwaggerJsonFormats.scala | 218 --------- .../xyz/driver/pdsuicommon/utils/FutureUtils.scala | 18 - .../xyz/driver/pdsuicommon/utils/Implicits.scala | 25 -- .../xyz/driver/pdsuicommon/utils/MapOps.scala | 10 - .../xyz/driver/pdsuicommon/utils/RandomUtils.scala | 19 - .../driver/pdsuicommon/utils/ServiceUtils.scala | 32 -- .../xyz/driver/pdsuicommon/utils/StringOps.scala | 23 - .../scala/xyz/driver/pdsuicommon/utils/Utils.scala | 43 -- .../pdsuicommon/validation/ValidationError.scala | 3 - .../driver/pdsuicommon/validation/Validators.scala | 39 -- .../xyz/driver/pdsuidomain/ListResponse.scala | 24 - .../xyz/driver/pdsuidomain/entities/Arm.scala | 20 - .../driver/pdsuidomain/entities/Criterion.scala | 57 --- .../driver/pdsuidomain/entities/DirectReport.scala | 24 - .../xyz/driver/pdsuidomain/entities/Document.scala | 492 --------------------- .../pdsuidomain/entities/DocumentHistory.scala | 98 ---- .../pdsuidomain/entities/DocumentIssue.scala | 24 - .../pdsuidomain/entities/EligibilityArm.scala | 42 -- .../pdsuidomain/entities/ExtractedData.scala | 48 -- .../driver/pdsuidomain/entities/Hypothesis.scala | 13 - .../driver/pdsuidomain/entities/Intervention.scala | 215 --------- .../xyz/driver/pdsuidomain/entities/Keyword.scala | 32 -- .../pdsuidomain/entities/MedicalRecord.scala | 164 ------- .../entities/MedicalRecordHistory.scala | 112 ----- .../pdsuidomain/entities/MedicalRecordIssue.scala | 24 - .../xyz/driver/pdsuidomain/entities/Message.scala | 35 -- .../xyz/driver/pdsuidomain/entities/Patient.scala | 63 --- .../pdsuidomain/entities/PatientCriterion.scala | 96 ---- .../entities/PatientEligibleTrial.scala | 94 ---- .../pdsuidomain/entities/PatientHistory.scala | 94 ---- .../pdsuidomain/entities/PatientHypothesis.scala | 20 - .../driver/pdsuidomain/entities/PatientIssue.scala | 22 - .../driver/pdsuidomain/entities/PatientLabel.scala | 47 -- .../entities/PatientLabelEvidenceView.scala | 29 -- .../pdsuidomain/entities/RawPatientDocument.scala | 30 -- .../entities/SlotArmEligibilityArm.scala | 13 - .../xyz/driver/pdsuidomain/entities/SlotArms.scala | 20 - .../xyz/driver/pdsuidomain/entities/Trial.scala | 126 ------ .../driver/pdsuidomain/entities/TrialHistory.scala | 100 ----- .../driver/pdsuidomain/entities/TrialIssue.scala | 24 - .../driver/pdsuidomain/entities/UserHistory.scala | 146 ------ .../driver/pdsuidomain/entities/eligibility.scala | 68 --- .../export/patient/ExportPatientLabel.scala | 15 - .../patient/ExportPatientLabelEvidence.scala | 21 - .../ExportPatientLabelEvidenceDocument.scala | 23 - .../export/patient/ExportPatientWithLabels.scala | 17 - .../entities/export/trial/ExportTrialArm.scala | 15 - .../export/trial/ExportTrialLabelCriterion.scala | 24 - .../export/trial/ExportTrialWithLabels.scala | 23 - .../driver/pdsuidomain/fakes/entities/common.scala | 123 ------ .../pdsuidomain/fakes/entities/eligibility.scala | 72 --- .../driver/pdsuidomain/fakes/entities/export.scala | 76 ---- .../fakes/entities/recordprocessing.scala | 322 -------------- .../fakes/entities/rep/DocumentGen.scala | 1 - .../fakes/entities/treatmentmatching.scala | 233 ---------- .../pdsuidomain/fakes/entities/trialcuration.scala | 239 ---------- .../xyz/driver/pdsuidomain/formats/json/arm.scala | 44 -- .../formats/json/bridgeuploadqueue.scala | 68 --- .../driver/pdsuidomain/formats/json/common.scala | 66 --- .../pdsuidomain/formats/json/criterion.scala | 175 -------- .../driver/pdsuidomain/formats/json/document.scala | 221 --------- .../pdsuidomain/formats/json/documenthistory.scala | 35 -- .../pdsuidomain/formats/json/documentissue.scala | 72 --- .../pdsuidomain/formats/json/eligibility.scala | 108 ----- .../pdsuidomain/formats/json/eligibilityarm.scala | 107 ----- .../driver/pdsuidomain/formats/json/export.scala | 127 ------ .../pdsuidomain/formats/json/extracteddata.scala | 155 ------- .../pdsuidomain/formats/json/hypothesis.scala | 12 - .../pdsuidomain/formats/json/intervention.scala | 147 ------ .../pdsuidomain/formats/json/listresponse.scala | 45 -- .../driver/pdsuidomain/formats/json/patient.scala | 118 ----- .../formats/json/patientcriterion.scala | 65 --- .../formats/json/patientdefiningcriteria.scala | 18 - .../formats/json/patienteligibletrial.scala | 39 -- .../pdsuidomain/formats/json/patienthistory.scala | 30 -- .../formats/json/patienthypothesis.scala | 35 -- .../pdsuidomain/formats/json/patientissue.scala | 58 --- .../pdsuidomain/formats/json/patientlabel.scala | 65 --- .../driver/pdsuidomain/formats/json/record.scala | 213 --------- .../pdsuidomain/formats/json/recordhistory.scala | 43 -- .../pdsuidomain/formats/json/recordissue.scala | 72 --- .../driver/pdsuidomain/formats/json/slotarm.scala | 44 -- .../pdsuidomain/formats/json/studydesign.scala | 29 -- .../driver/pdsuidomain/formats/json/trial.scala | 187 -------- .../pdsuidomain/formats/json/trialhistory.scala | 32 -- .../pdsuidomain/formats/json/trialissue.scala | 134 ------ .../driver/pdsuidomain/services/ArmService.scala | 130 ------ .../pdsuidomain/services/CriterionService.scala | 126 ------ .../services/DocumentHistoryService.scala | 45 -- .../services/DocumentIssueService.scala | 95 ---- .../pdsuidomain/services/DocumentService.scala | 147 ------ .../pdsuidomain/services/DocumentTypeService.scala | 26 -- .../services/EligibilityArmService.scala | 145 ------ .../services/EligibilitySnapshotService.scala | 16 - .../services/EligibilityVerificationService.scala | 22 - .../services/ExtractedDataService.scala | 126 ------ .../pdsuidomain/services/HypothesisService.scala | 69 --- .../pdsuidomain/services/InterventionService.scala | 119 ----- .../services/InterventionTypeService.scala | 28 -- .../services/MedicalRecordHistoryService.scala | 45 -- .../services/MedicalRecordIssueService.scala | 95 ---- .../services/MedicalRecordService.scala | 126 ------ .../services/PatientCriterionService.scala | 28 -- .../services/PatientEligibleTrialService.scala | 29 -- .../services/PatientHistoryService.scala | 20 - .../services/PatientHypothesisService.scala | 25 -- .../pdsuidomain/services/PatientIssueService.scala | 32 -- .../services/PatientLabelEvidenceService.scala | 24 - .../pdsuidomain/services/PatientLabelService.scala | 31 -- .../pdsuidomain/services/PatientService.scala | 39 -- .../pdsuidomain/services/ProviderTypeService.scala | 27 -- .../pdsuidomain/services/QueueUploadService.scala | 80 ---- .../pdsuidomain/services/SlotArmService.scala | 130 ------ .../pdsuidomain/services/StudyDesignService.scala | 28 -- .../pdsuidomain/services/TrialHistoryService.scala | 45 -- .../pdsuidomain/services/TrialIssueService.scala | 95 ---- .../driver/pdsuidomain/services/TrialService.scala | 158 ------- .../fake/FakeEligibilityVerificationService.scala | 32 -- .../services/fake/FakeTrialService.scala | 136 ------ .../pdsuidomain/services/rest/RestArmService.scala | 85 ---- .../services/rest/RestCriterionService.scala | 88 ---- .../services/rest/RestDocumentService.scala | 121 ----- .../services/rest/RestDocumentTypeService.scala | 33 -- .../rest/RestEligibilitySnapshotService.scala | 34 -- .../rest/RestEligibilityVerificationService.scala | 53 --- .../services/rest/RestExtractedDataService.scala | 100 ----- .../pdsuidomain/services/rest/RestHelper.scala | 107 ----- .../services/rest/RestHypothesisService.scala | 60 --- .../services/rest/RestInterventionService.scala | 88 ---- .../rest/RestInterventionTypeService.scala | 37 -- .../services/rest/RestMedicalRecordService.scala | 129 ------ .../rest/RestPatientCriterionService.scala | 81 ---- .../services/rest/RestPatientLabelService.scala | 84 ---- .../services/rest/RestPatientService.scala | 78 ---- .../services/rest/RestProviderTypeService.scala | 34 -- .../services/rest/RestStudyDesignService.scala | 34 -- .../services/rest/RestTrialIssueService.scala | 103 ----- .../services/rest/RestTrialService.scala | 173 -------- .../restquery/db/SlickPostgresQueryBuilder.scala | 116 +++++ .../driver/restquery/db/SlickQueryBuilder.scala | 387 ++++++++++++++++ .../restquery/db/SlickQueryBuilderParameters.scala | 240 ++++++++++ .../xyz/driver/restquery/query/Pagination.scala | 12 + .../query/SearchFilterBinaryOperation.scala | 5 + .../driver/restquery/query/SearchFilterExpr.scala | 196 ++++++++ .../query/SearchFilterNAryOperation.scala | 5 + .../scala/xyz/driver/restquery/query/Sorting.scala | 56 +++ .../xyz/driver/restquery/rest/Directives.scala | 55 +++ .../restquery/rest/parsers/DimensionsParser.scala | 30 ++ .../restquery/rest/parsers/PaginationParser.scala | 23 + .../rest/parsers/ParseQueryArgException.scala | 3 + .../rest/parsers/SearchFilterParser.scala | 178 ++++++++ .../restquery/rest/parsers/SortingParser.scala | 64 +++ .../scala/xyz/driver/restquery/utils/Utils.scala | 79 ++++ .../pdsuicommon/db/SearchFilterExprSuite.scala | 34 -- .../error/UnexpectedFilterException.scala | 3 - .../logging/PhiStringContextSuite.scala | 31 -- .../parsers/PaginationParserSuite.scala | 103 ----- .../parsers/SearchFilterParserSuite.scala | 260 ----------- .../pdsuicommon/parsers/SortingParserSuite.scala | 96 ---- .../xyz/driver/pdsuicommon/parsers/TestUtils.scala | 53 --- .../driver/pdsuicommon/utils/StringOpsSuite.scala | 33 -- .../xyz/driver/pdsuidomain/DocumentSuite.scala | 94 ---- .../pdsuidomain/formats/json/ArmFormatSuite.scala | 37 -- .../json/BridgeUploadQueueFormatSuite.scala | 32 -- .../formats/json/CriterionFormatSuite.scala | 75 ---- .../formats/json/DocumentFormatSuite.scala | 73 --- .../formats/json/DocumentHistoryFormatSuite.scala | 49 -- .../formats/json/DocumentIssueFormatSuite.scala | 48 -- .../EligibilityArmWithDiseasesFormatSuite.scala | 56 --- .../formats/json/ExportFormatSuite.scala | 129 ------ .../formats/json/ExtractedDataFormatSuite.scala | 109 ----- .../formats/json/HypothesisFormatSuite.scala | 27 -- .../formats/json/InterventionFormatSuite.scala | 73 --- .../formats/json/ListResponseFormatSuite.scala | 102 ----- .../formats/json/MedicalRecordFormatSuite.scala | 152 ------- .../json/MedicalRecordHistoryFormatSuite.scala | 51 --- .../json/MedicalRecordIssueFormatSuite.scala | 47 -- .../formats/json/PatientCriterionFormatSuite.scala | 60 --- .../json/PatientEligibleTrialFormatSuite.scala | 61 --- .../formats/json/PatientFormatSuite.scala | 41 -- .../formats/json/PatientHistoryFormatSuite.scala | 32 -- .../json/PatientHypothesisFormatSuite.scala | 28 -- .../formats/json/PatientIssueFormatSuite.scala | 45 -- .../formats/json/PatientLabelFormatSuite.scala | 78 ---- .../formats/json/SlotArmFormatSuite.scala | 36 -- .../formats/json/StudyDesignFormatSuite.scala | 20 - .../formats/json/TrialFormatSuite.scala | 49 -- .../formats/json/TrialHistoryFormatSuite.scala | 32 -- .../formats/json/TrialIssueFormatSuite.scala | 50 --- .../restquery/db/SearchFilterExprSuite.scala | 34 ++ .../rest/parsers/PaginationParserSuite.scala | 103 +++++ .../rest/parsers/SearchFilterParserSuite.scala | 259 +++++++++++ .../rest/parsers/SortingParserSuite.scala | 96 ++++ .../driver/restquery/rest/parsers/TestUtils.scala | 54 +++ .../driver/restquery/utils/StringOpsSuite.scala | 33 ++ 253 files changed, 2028 insertions(+), 15757 deletions(-) delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/Config.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/compat/EitherOps.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/compat/Implicits.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcExecutionContext.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcThreadFactory.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/db/SlickPostgresQueryBuilder.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/db/repositories/Repository.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/db/repositories/RepositoryLogging.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/error/ErrorCode.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/error/ExceptionFormatter.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/error/FailedValidationException.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/error/IncorrectIdException.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientUploader.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/http/package.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/json/JsonSerializer.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/logging/DefaultPhiLogger.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/logging/Implicits.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogger.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogging.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/logging/PhiString.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/logging/PhiStringContext.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/logging/TimeLogger.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/logging/package.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/parsers/PaginationParser.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/parsers/ParseQueryArgException.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/parsers/SortingParser.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/serialization/Marshaller.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDataSource.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbAction.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbDiff.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/synchronization/domain/FakeId.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/FakeIdGen.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/Refiner.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/package.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/utils/CharOps.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/utils/CustomSwaggerJsonFormats.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/utils/MapOps.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/utils/RandomUtils.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/utils/ServiceUtils.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/utils/StringOps.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/utils/Utils.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/validation/ValidationError.scala delete mode 100644 src/main/scala/xyz/driver/pdsuicommon/validation/Validators.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/ListResponse.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/Arm.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/DirectReport.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/Document.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/DocumentHistory.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/DocumentIssue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/EligibilityArm.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/Hypothesis.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/Keyword.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecord.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordHistory.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordIssue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/Message.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/Patient.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/PatientCriterion.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/PatientEligibleTrial.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/PatientHistory.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/PatientHypothesis.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/PatientIssue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/PatientLabel.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/PatientLabelEvidenceView.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/RawPatientDocument.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/SlotArmEligibilityArm.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/SlotArms.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/TrialHistory.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/TrialIssue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/UserHistory.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/eligibility.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabel.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidence.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidenceDocument.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientWithLabels.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/fakes/entities/common.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/fakes/entities/eligibility.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/fakes/entities/recordprocessing.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/fakes/entities/rep/DocumentGen.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/fakes/entities/treatmentmatching.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/fakes/entities/trialcuration.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/arm.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/bridgeuploadqueue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/common.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/document.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/documenthistory.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/documentissue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibility.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/export.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/hypothesis.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/listresponse.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/patient.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/patientcriterion.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/patientdefiningcriteria.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/patienteligibletrial.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/patienthistory.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/patienthypothesis.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/patientissue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/patientlabel.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/record.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/recordhistory.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/recordissue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/studydesign.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/trial.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/trialhistory.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/trialissue.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/DocumentHistoryService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/DocumentIssueService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/EligibilityArmService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/EligibilitySnapshotService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/EligibilityVerificationService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordHistoryService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordIssueService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/PatientHistoryService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/PatientIssueService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/QueueUploadService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/SlotArmService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/TrialHistoryService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/TrialIssueService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeEligibilityVerificationService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestArmService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestCriterionService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestDocumentService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestDocumentTypeService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilitySnapshotService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilityVerificationService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestExtractedDataService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionTypeService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestMedicalRecordService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientCriterionService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientLabelService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestProviderTypeService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestStudyDesignService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestTrialIssueService.scala delete mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/rest/RestTrialService.scala create mode 100644 src/main/scala/xyz/driver/restquery/db/SlickPostgresQueryBuilder.scala create mode 100644 src/main/scala/xyz/driver/restquery/db/SlickQueryBuilder.scala create mode 100644 src/main/scala/xyz/driver/restquery/db/SlickQueryBuilderParameters.scala create mode 100644 src/main/scala/xyz/driver/restquery/query/Pagination.scala create mode 100644 src/main/scala/xyz/driver/restquery/query/SearchFilterBinaryOperation.scala create mode 100644 src/main/scala/xyz/driver/restquery/query/SearchFilterExpr.scala create mode 100644 src/main/scala/xyz/driver/restquery/query/SearchFilterNAryOperation.scala create mode 100644 src/main/scala/xyz/driver/restquery/query/Sorting.scala create mode 100644 src/main/scala/xyz/driver/restquery/rest/Directives.scala create mode 100644 src/main/scala/xyz/driver/restquery/rest/parsers/DimensionsParser.scala create mode 100644 src/main/scala/xyz/driver/restquery/rest/parsers/PaginationParser.scala create mode 100644 src/main/scala/xyz/driver/restquery/rest/parsers/ParseQueryArgException.scala create mode 100644 src/main/scala/xyz/driver/restquery/rest/parsers/SearchFilterParser.scala create mode 100644 src/main/scala/xyz/driver/restquery/rest/parsers/SortingParser.scala create mode 100644 src/main/scala/xyz/driver/restquery/utils/Utils.scala delete mode 100644 src/test/scala/xyz/driver/pdsuicommon/db/SearchFilterExprSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuicommon/error/UnexpectedFilterException.scala delete mode 100644 src/test/scala/xyz/driver/pdsuicommon/logging/PhiStringContextSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuicommon/parsers/PaginationParserSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParserSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuicommon/parsers/SortingParserSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuicommon/parsers/TestUtils.scala delete mode 100644 src/test/scala/xyz/driver/pdsuicommon/utils/StringOpsSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/DocumentSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/ArmFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/BridgeUploadQueueFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/CriterionFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentHistoryFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentIssueFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/EligibilityArmWithDiseasesFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/ExportFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/ExtractedDataFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/HypothesisFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/InterventionFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/ListResponseFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordHistoryFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordIssueFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientCriterionFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientEligibleTrialFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientHistoryFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientHypothesisFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientIssueFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientLabelFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/SlotArmFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/StudyDesignFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialHistoryFormatSuite.scala delete mode 100644 src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialIssueFormatSuite.scala create mode 100644 src/test/scala/xyz/driver/restquery/db/SearchFilterExprSuite.scala create mode 100644 src/test/scala/xyz/driver/restquery/rest/parsers/PaginationParserSuite.scala create mode 100644 src/test/scala/xyz/driver/restquery/rest/parsers/SearchFilterParserSuite.scala create mode 100644 src/test/scala/xyz/driver/restquery/rest/parsers/SortingParserSuite.scala create mode 100644 src/test/scala/xyz/driver/restquery/rest/parsers/TestUtils.scala create mode 100644 src/test/scala/xyz/driver/restquery/utils/StringOpsSuite.scala diff --git a/src/main/scala/xyz/driver/pdsuicommon/Config.scala b/src/main/scala/xyz/driver/pdsuicommon/Config.scala deleted file mode 100644 index 25686b8..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/Config.scala +++ /dev/null @@ -1,21 +0,0 @@ -package xyz.driver.pdsuicommon - -import pureconfig._ - -import scala.util.{Failure, Success, Try} - -object Config { - - implicit def productHint[T]: ProductHint[T] = ProductHint(ConfigFieldMapping(CamelCase, CamelCase)) - - def loadConfig[Config](implicit reader: ConfigReader[Config]): Try[Config] = pureconfig.loadConfig match { - case Right(x) => Success(x) - case Left(e) => Failure(new RuntimeException(e.toString)) - } - - def loadConfig[Config](namespace: String)(implicit reader: ConfigReader[Config]): Try[Config] = - pureconfig.loadConfig(namespace) match { - case Right(x) => Success(x) - case Left(e) => Failure(new RuntimeException(e.toString)) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala deleted file mode 100644 index e4c907e..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala +++ /dev/null @@ -1,280 +0,0 @@ -package xyz.driver.pdsuicommon.acl - -import xyz.driver.core.auth.Role -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.auth._ -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.logging._ - -/** - * @see https://driverinc.atlassian.net/wiki/display/RA/User+permissions#UserPermissions-AccessControlList - */ -object ACL extends PhiLogging { - - type AclCheck = Role => Boolean - - val Forbid: AclCheck = _ => false - - val Allow: AclCheck = _ => true - - val RepRoles: Set[Role] = Set[Role](RecordAdmin, RecordCleaner, RecordOrganizer, DocumentExtractor) - - val TcRoles: Set[Role] = Set[Role](TrialSummarizer, CriteriaCurator, TrialAdmin) - - val TreatmentMatchingRoles: Set[Role] = Set[Role](RoutesCurator, EligibilityVerifier, TreatmentMatchingAdmin) - - val PepRoles: Set[Role] = Set[Role](ResearchOncologist) - - val All: Set[Role] = RepRoles ++ TcRoles ++ TreatmentMatchingRoles ++ PepRoles + AdministratorRole - - // Common - - object UserHistory - extends BaseACL( - label = "user history", - read = Set(TreatmentMatchingAdmin) - ) - - object Queue - extends BaseACL( - label = "queue", - create = Set(AdministratorRole), - read = Set(AdministratorRole), - update = Set(AdministratorRole) - ) - - // REP - - object MedicalRecord - extends BaseACL( - label = "medical record", - read = RepRoles ++ TreatmentMatchingRoles + ResearchOncologist + AdministratorRole, - update = RepRoles - DocumentExtractor - ) - - object MedicalRecordHistory - extends BaseACL( - label = "medical record history", - read = Set(RecordAdmin) - ) - - object MedicalRecordIssue - extends BaseACL( - label = "medical record issue", - create = Set(RecordCleaner, RecordOrganizer, RecordAdmin), - read = Set(RecordCleaner, RecordOrganizer, RecordAdmin), - update = Set(RecordCleaner, RecordOrganizer, RecordAdmin), - delete = Set(RecordCleaner, RecordOrganizer, RecordAdmin) - ) - - object Document - extends BaseACL( - label = "document", - create = Set(RecordOrganizer, RecordAdmin), - read = RepRoles - RecordCleaner ++ TreatmentMatchingRoles + ResearchOncologist, - update = RepRoles - RecordCleaner, - delete = Set(RecordOrganizer, RecordAdmin) - ) - - object DocumentHistory - extends BaseACL( - label = "document history", - read = Set(RecordAdmin) - ) - - object DocumentIssue - extends BaseACL( - label = "document issue", - create = Set(RecordAdmin, DocumentExtractor), - read = Set(RecordAdmin, DocumentExtractor), - update = Set(RecordAdmin, DocumentExtractor), - delete = Set(RecordAdmin, DocumentExtractor) - ) - - object ExtractedData - extends BaseACL( - label = "extracted data", - create = Set(DocumentExtractor, RecordAdmin), - read = Set(DocumentExtractor, RecordAdmin) ++ TreatmentMatchingRoles + ResearchOncologist, - update = Set(DocumentExtractor, RecordAdmin), - delete = Set(DocumentExtractor, RecordAdmin) - ) - - object ProviderType - extends BaseACL( - label = "provider type", - read = RepRoles ++ TreatmentMatchingRoles + ResearchOncologist - ) - - object DocumentType - extends BaseACL( - label = "document type", - read = RepRoles ++ TreatmentMatchingRoles + ResearchOncologist - ) - - object Message - extends BaseACL( - label = "message", - create = RepRoles ++ TreatmentMatchingRoles, - read = RepRoles ++ TreatmentMatchingRoles, - update = RepRoles ++ TreatmentMatchingRoles, - delete = RepRoles ++ TreatmentMatchingRoles - ) - - // TC - - object Trial - extends BaseACL( - label = "trial", - read = TcRoles ++ TreatmentMatchingRoles + ResearchOncologist + AdministratorRole, - update = TcRoles - ) - - object TrialHistory - extends BaseACL( - label = "trial history", - read = TcRoles - ) - - object TrialIssue - extends BaseACL( - label = "trial issue", - create = TcRoles, - read = TcRoles, - update = TcRoles, - delete = TcRoles - ) - - object StudyDesign - extends BaseACL( - label = "study design", - read = Set(TrialSummarizer, TrialAdmin) - ) - - object Hypothesis - extends BaseACL( - label = "hypothesis", - read = Set(TrialSummarizer, TrialAdmin) ++ TreatmentMatchingRoles, - create = Set(TrialAdmin), - delete = Set(TrialAdmin) - ) - - object Criterion - extends BaseACL( - label = "criterion", - create = Set(CriteriaCurator, TrialAdmin), - read = Set(CriteriaCurator, TrialAdmin, RoutesCurator, TreatmentMatchingAdmin, ResearchOncologist), - update = Set(CriteriaCurator, TrialAdmin), - delete = Set(CriteriaCurator, TrialAdmin) - ) - - object Arm - extends BaseACL( - label = "arm", - create = Set(TrialSummarizer, TrialAdmin), - read = TcRoles, - update = Set(TrialSummarizer, TrialAdmin), - delete = Set(TrialSummarizer, TrialAdmin) - ) - - object Intervention - extends BaseACL( - label = "intervention", - create = Set(TrialSummarizer, TrialAdmin), - read = Set(TrialSummarizer, TrialAdmin), - update = Set(TrialSummarizer, TrialAdmin), - delete = Set(TrialSummarizer, TrialAdmin) - ) - - object InterventionType - extends BaseACL( - label = "intervention type", - read = Set(TrialSummarizer, TrialAdmin) - ) - - // EV - - object Patient - extends BaseACL( - label = "patient", - read = TreatmentMatchingRoles + ResearchOncologist + AdministratorRole, - update = TreatmentMatchingRoles - ) - - object PatientHistory - extends BaseACL( - label = "patient history", - read = Set(TreatmentMatchingAdmin) - ) - - object PatientIssue - extends BaseACL( - label = "patient issue", - create = TreatmentMatchingRoles, - read = TreatmentMatchingRoles, - update = TreatmentMatchingRoles, - delete = TreatmentMatchingRoles - ) - - object PatientLabel - extends BaseACL( - label = "patient label", - read = TreatmentMatchingRoles + ResearchOncologist, - update = TreatmentMatchingRoles - ) - - object PatientCriterion - extends BaseACL( - label = "patient criterion", - read = TreatmentMatchingRoles + ResearchOncologist, - update = TreatmentMatchingRoles - ) - - object PatientLabelEvidence - extends BaseACL( - label = "patient label evidence", - read = TreatmentMatchingRoles + ResearchOncologist - ) - - object EligibleTrial - extends BaseACL( - label = "eligible trial", - read = Set(RoutesCurator, TreatmentMatchingAdmin, ResearchOncologist), - update = Set(RoutesCurator, TreatmentMatchingAdmin) - ) - - object PatientHypothesis - extends BaseACL( - label = "patient hypothesis", - read = Set(RoutesCurator, TreatmentMatchingAdmin), - update = Set(RoutesCurator, TreatmentMatchingAdmin) - ) - - // Utility code - - abstract class BaseACL(label: String, - create: AclCheck = Forbid, - read: AclCheck = Forbid, - update: AclCheck = Forbid, - delete: AclCheck = Forbid) { - - def isCreateAllow()(implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Boolean = - check("create", create)(requestContext.authenticatedUser.roles) - - def isReadAllow()(implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Boolean = - check("read", read)(requestContext.authenticatedUser.roles) - - def isUpdateAllow()(implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Boolean = - check("update", update)(requestContext.authenticatedUser.roles) - - def isDeleteAllow()(implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Boolean = - check("delete", delete)(requestContext.authenticatedUser.roles) - - private def check(action: String, isAllowed: AclCheck)(executorRoles: Set[Role]): Boolean = { - loggedError( - executorRoles.exists(isAllowed) || executorRoles.contains(AdministratorRole), - phi"${Unsafe(executorRoles.mkString(", "))} has no access to ${Unsafe(action)} a ${Unsafe(label)}" - ) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/compat/EitherOps.scala b/src/main/scala/xyz/driver/pdsuicommon/compat/EitherOps.scala deleted file mode 100644 index d069f86..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/compat/EitherOps.scala +++ /dev/null @@ -1,14 +0,0 @@ -package xyz.driver.pdsuicommon.compat - -final class EitherOps[A, B](val self: Either[A, B]) extends AnyVal { - - def map[B2](f: B => B2): Either[A, B2] = flatMap { x => - Right(f(x)) - } - - def flatMap[B2](f: B => Either[A, B2]): Either[A, B2] = self match { - case Left(x) => Left(x) - case Right(x) => f(x) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/compat/Implicits.scala b/src/main/scala/xyz/driver/pdsuicommon/compat/Implicits.scala deleted file mode 100644 index 147c9e8..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/compat/Implicits.scala +++ /dev/null @@ -1,7 +0,0 @@ -package xyz.driver.pdsuicommon.compat - -object Implicits { - - implicit def toEitherOps[A, B](self: Either[A, B]): EitherOps[A, B] = new EitherOps(self) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala b/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala deleted file mode 100644 index a9430e3..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala +++ /dev/null @@ -1,124 +0,0 @@ -package xyz.driver.pdsuicommon.computation - -import scala.concurrent.{ExecutionContext, Future} - -/** - * Takes care of computations - * - * Success(either) - the computation will be continued. - * Failure(error) - the computation was failed with unhandled error. - * - * Either[Result, T]: - * Left(result) is a final and handled result, another computations (map, flatMap) will be ignored. - * Right(T) is a current result. Functions in map/flatMap will continue the computation. - * - * Example: - * {{{ - * import scala.concurrent.ExecutionContext.Implicits.global - * import scala.concurrent.{ExecutionContext, Future} - * import xyz.driver.pdsuicommon.computation.Computation - * - * def successful = for { - * x <- Computation.continue(1) - * y <- Computation.continue(2) - * } yield s"\$x + \$y" - * - * // Prints "Success(1 + 2)" - * successful.join.onComplete(print) - * - * def failed = for { - * x <- Computation.abort("Failed on x") - * _ = print("Second step") - * y <- Computation.continue(2) - * } yield s"\$x + \$y" - * - * // Prints "Success(Failed on x)" - * failed.join.onComplete(print) - * }}} - * - * TODO: Make future private - * - * @param future The final flow in a future. - * @tparam R Type of result for aborted computation. - * @tparam T Type of result for continued computation. - */ -final case class Computation[+R, +T](future: Future[Either[R, T]]) { - - def flatMap[R2, T2](f: T => Computation[R2, T2])(implicit ec: ExecutionContext, ev: R <:< R2): Computation[R2, T2] = { - Computation(future.flatMap { - case Left(x) => Future.successful(Left(x)) - case Right(x) => f(x).future - }) - } - - def processExceptions[R2](f: PartialFunction[Throwable, R2])(implicit ev1: R <:< R2, - ec: ExecutionContext): Computation[R2, T] = { - val strategy = f.andThen(x => Left(x): Either[R2, T]) - val castedFuture: Future[Either[R2, T]] = future.map { - case Left(x) => Left(x) - case Right(x) => Right(x) - } - Computation(castedFuture.recover(strategy)) - } - - def map[T2](f: T => T2)(implicit ec: ExecutionContext): Computation[R, T2] = flatMap { a => - Computation.continue(f(a)) - } - - def mapLeft[R2](f: R => R2)(implicit ec: ExecutionContext): Computation[R2, T] = { - Computation(future.map { - case Left(x) => Left(f(x)) - case Right(x) => Right(x) - }) - } - - def mapAll[R2, T2](onLeft: R => Computation[R2, T2])(onRight: T => Computation[R2, T2])( - onFailure: () => Computation[R2, T2])(implicit ec: ExecutionContext): Computation[R2, T2] = { - - Computation(future.flatMap(_.fold(onLeft, onRight).future).recoverWith { - case _ => onFailure().future - }) - } - - def andThen(f: T => Any)(implicit ec: ExecutionContext): Computation[R, T] = map { a => - f(a) - a - } - - def filter(f: T => Boolean)(implicit ec: ExecutionContext): Computation[R, T] = map { a => - if (f(a)) a - else throw new NoSuchElementException("When filtering") - } - - def withFilter(f: T => Boolean)(implicit ec: ExecutionContext): Computation[R, T] = filter(f) - - def foreach[T2](f: T => T2)(implicit ec: ExecutionContext): Unit = future.foreach { - case Right(x) => f(x) - case _ => - } - - def toFuture[R2](resultFormatter: T => R2)(implicit ec: ExecutionContext, ev: R <:< R2): Future[R2] = future.map { - case Left(x) => x - case Right(x) => resultFormatter(x) - } - - def toFuture[R2](implicit ec: ExecutionContext, ev1: R <:< R2, ev2: T <:< R2): Future[R2] = future.map { - case Left(x) => x - case Right(x) => x - } -} - -object Computation { - - def continue[T](x: T): Computation[Nothing, T] = Computation(Future.successful(Right(x))) - - def abort[R](result: R): Computation[R, Nothing] = Computation(Future.successful(Left(result))) - - def fail(exception: Throwable): Computation[Nothing, Nothing] = Computation(Future.failed(exception)) - - def fromFuture[T](input: Future[T])(implicit ec: ExecutionContext): Computation[Nothing, T] = Computation { - input.map { x => - Right(x) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala deleted file mode 100644 index 8213262..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala +++ /dev/null @@ -1,84 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import java.time.LocalDateTime - -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item -import xyz.driver.pdsuicommon.logging._ - -import scala.concurrent.Future - -object BridgeUploadQueue { - - /** - * @param kind For example documents - * @param tag For example, a patient's id: 1 - * @param attempts Which attempt - * @param created When the task was created - * @param nextAttempt Time of the next attempt - */ - final case class Item(kind: String, - tag: String, - created: LocalDateTime, - attempts: Int, - nextAttempt: LocalDateTime, - completed: Boolean, - dependencyKind: Option[String], - dependencyTag: Option[String]) { - - def dependency: Option[Dependency] = { - dependencyKind - .zip(dependencyTag) - .headOption - .map(Function.tupled(Dependency.apply)) - } - - } - - object Item { - - implicit def toPhiString(x: Item): PhiString = { - import x._ - phi"BridgeUploadQueue.Item(kind=${Unsafe(kind)}, tag=${Unsafe(tag)}, " + - phi"attempts=${Unsafe(attempts)}, start=$created, nextAttempt=$nextAttempt, completed=$completed, " + - phi"dependency=$dependency)" - } - - def apply(kind: String, tag: String, dependency: Option[Dependency] = None): Item = { - val now = LocalDateTime.now() - - Item( - kind = kind, - tag = tag, - created = now, - attempts = 0, - nextAttempt = now, - completed = false, - dependencyKind = dependency.map(_.kind), - dependencyTag = dependency.map(_.tag) - ) - } - - } - - final case class Dependency(kind: String, tag: String) - - object Dependency { - - implicit def toPhiString(x: Dependency): PhiString = { - import x._ - phi"Dependency(kind=${Unsafe(kind)}, tag=${Unsafe(tag)})" - } - } -} - -trait BridgeUploadQueue { - - def add(item: Item): Future[Item] - - def get(kind: String): Future[Option[Item]] - - def complete(kind: String, tag: String): Future[Unit] - - def tryRetry(item: Item): Future[Option[Item]] - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala deleted file mode 100644 index 6659088..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala +++ /dev/null @@ -1,93 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import java.io.Closeable -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.atomic.AtomicBoolean -import java.util.{Timer, TimerTask} - -import com.typesafe.scalalogging.StrictLogging -import org.slf4j.MDC -import xyz.driver.pdsuicommon.error.ExceptionFormatter -import xyz.driver.pdsuicommon.utils.RandomUtils - -import scala.concurrent.duration.FiniteDuration -import scala.concurrent.{ExecutionContext, Future} -import scala.util.{Failure, Success, Try} - -class Cron(settings: Cron.Settings) extends Closeable with StrictLogging { - - import Cron._ - - private val timer = new Timer("cronTimer", true) - - private val jobs = ConcurrentHashMap.newKeySet[String]() - - def register(name: String)(job: () => Future[Unit])(implicit ec: ExecutionContext): Unit = { - logger.trace("register({})", name) - val disableList = settings.disable.split(",").map(_.trim).toList - if (disableList.contains(name)) logger.info("The task '{}' is disabled", name) - else { - settings.intervals.get(name) match { - case None => - logger.error("Can not find an interval for task '{}', check the settings", name) - throw new IllegalArgumentException(s"Can not find an interval for task '$name', check the settings") - - case Some(period) => - logger.info("register a new task '{}' with a period of {}ms", name, period.toMillis.asInstanceOf[AnyRef]) - timer.schedule(new SingletonTask(name, job), 0, period.toMillis) - } - } - - jobs.add(name) - } - - /** - * Checks unused jobs - */ - def verify(): Unit = { - import scala.collection.JavaConverters._ - - val unusedJobs = settings.intervals.keySet -- jobs.asScala.toSet - unusedJobs.foreach { job => - logger.warn(s"The job '$job' is listed, but not registered or ignored") - } - } - - override def close(): Unit = { - timer.cancel() - } -} - -object Cron { - - final case class Settings(disable: String, intervals: Map[String, FiniteDuration]) - - private class SingletonTask(taskName: String, job: () => Future[Unit])(implicit ec: ExecutionContext) - extends TimerTask with StrictLogging { - - private val isWorking = new AtomicBoolean(false) - - override def run(): Unit = { - if (isWorking.compareAndSet(false, true)) { - MDC.put("userId", "cron") - MDC.put("requestId", RandomUtils.randomString(15)) - - logger.info("Start '{}'", taskName) - Try { - job() - .andThen { - case Success(_) => logger.info("'{}' is completed", taskName) - case Failure(e) => logger.error(s"Job '{}' is failed: ${ExceptionFormatter.format(e)}", taskName) - } - .onComplete(_ => isWorking.set(false)) - } match { - case Success(_) => - case Failure(e) => - logger.error("Can't start '{}'", taskName, e) - } - } else { - logger.debug("The previous job '{}' is in progress", taskName) - } - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala deleted file mode 100644 index 658b5b1..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala +++ /dev/null @@ -1,37 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import java.util.concurrent.LinkedBlockingQueue -import java.util.function.Predicate - -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item -import xyz.driver.pdsuicommon.logging.PhiLogging - -import scala.collection.JavaConverters._ -import scala.concurrent.Future - -/** - * Use it only for tests - */ -class InMemoryBridgeUploadQueue extends BridgeUploadQueue with PhiLogging { - - private val queue = new LinkedBlockingQueue[Item]() - - override def add(item: Item): Future[Item] = { - queue.add(item) - Future.successful(item) - } - - override def tryRetry(item: Item): Future[Option[Item]] = Future.successful(Some(item)) - - override def get(kind: String): Future[Option[Item]] = { - val r = queue.iterator().asScala.find(_.kind == kind) - Future.successful(r) - } - - override def complete(kind: String, tag: String): Future[Unit] = { - queue.removeIf(new Predicate[Item] { - override def test(t: Item): Boolean = t.kind == kind && t.tag == tag - }) - Future.successful(()) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcExecutionContext.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcExecutionContext.scala deleted file mode 100644 index 3dee8ea..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcExecutionContext.scala +++ /dev/null @@ -1,35 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import org.slf4j.MDC - -import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} - -object MdcExecutionContext { - def from(orig: ExecutionContext): ExecutionContext = new MdcExecutionContext(orig) -} - -class MdcExecutionContext(orig: ExecutionContext) extends ExecutionContextExecutor { - - def execute(runnable: Runnable): Unit = { - val parentMdcContext = MDC.getCopyOfContextMap - - orig.execute(new Runnable { - def run(): Unit = { - val saveMdcContext = MDC.getCopyOfContextMap - setContextMap(parentMdcContext) - - try { - runnable.run() - } finally { - setContextMap(saveMdcContext) - } - } - }) - } - - private[this] def setContextMap(context: java.util.Map[String, String]): Unit = - Option(context).fold(MDC.clear())(MDC.setContextMap) - - def reportFailure(t: Throwable): Unit = orig.reportFailure(t) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcThreadFactory.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcThreadFactory.scala deleted file mode 100644 index d1dc3ae..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcThreadFactory.scala +++ /dev/null @@ -1,33 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import java.util.concurrent.ThreadFactory - -import org.slf4j.MDC - -object MdcThreadFactory { - def from(orig: ThreadFactory): ThreadFactory = new MdcThreadFactory(orig) -} - -class MdcThreadFactory(orig: ThreadFactory) extends ThreadFactory { - - override def newThread(runnable: Runnable): Thread = { - val parentMdcContext = MDC.getCopyOfContextMap - - orig.newThread(new Runnable { - def run(): Unit = { - val saveMdcContext = MDC.getCopyOfContextMap - setContextMap(parentMdcContext) - - try { - runnable.run() - } finally { - setContextMap(saveMdcContext) - } - } - }) - } - - private[this] def setContextMap(context: java.util.Map[String, String]): Unit = - Option(context).fold(MDC.clear())(MDC.setContextMap) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala deleted file mode 100644 index 2f7fe6c..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala +++ /dev/null @@ -1,60 +0,0 @@ -package xyz.driver.pdsuicommon.concurrent - -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Dependency -import xyz.driver.pdsuicommon.concurrent.SafeBridgeUploadQueue.{DependencyResolver, SafeTask, Tag} -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.serialization.Marshaller - -import scala.concurrent.{ExecutionContext, Future} - -object SafeBridgeUploadQueue { - - trait Tag extends Product with Serializable - - final case class SafeTask[T <: Tag](tag: T, private[SafeBridgeUploadQueue] val queueItem: BridgeUploadQueue.Item) - - object SafeTask { - implicit def toPhiString[T <: Tag](x: SafeTask[T]): PhiString = { - import x._ - phi"SafeTask(tag=${Unsafe(tag)}, $queueItem)" - } - } - - trait DependencyResolver[T <: Tag] { - def getDependency(tag: T): Option[Dependency] - } - -} - -class SafeBridgeUploadQueue[T <: Tag](kind: String, origQueue: BridgeUploadQueue)( - implicit tagMarshaller: Marshaller[T, String], - dependencyResolver: DependencyResolver[T], - executionContext: ExecutionContext) { - - type Task = SafeTask[T] - - def add(tag: T): Future[BridgeUploadQueue.Item] = - origQueue.add( - BridgeUploadQueue.Item( - kind = kind, - tag = tagMarshaller.write(tag), - dependency = dependencyResolver.getDependency(tag) - )) - - def tryRetry(task: Task): Future[Option[Task]] = wrap(origQueue.tryRetry(task.queueItem)) - - def get: Future[Option[Task]] = wrap(origQueue.get(kind)) - - def complete(tag: T): Future[Unit] = origQueue.complete(kind, tagMarshaller.write(tag)) - - private def wrap(x: Future[Option[BridgeUploadQueue.Item]]): Future[Option[Task]] = x.map(_.map(cover)) - - private def cover(rawTask: BridgeUploadQueue.Item): Task = { - val tag = tagMarshaller - .read(rawTask.tag) - .getOrElse(throw new IllegalArgumentException(s"Can not parse tag '${rawTask.tag}'")) - - SafeTask(tag, rawTask) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala b/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala deleted file mode 100644 index 7c290d1..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala +++ /dev/null @@ -1,13 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import scala.concurrent.Future - -/** - * Where queries should run - */ -trait DbIo { - def runAsync[T](f: => T): Future[T] - def runSync[T](f: => T): T = f - def runAsyncTx[T](f: => T): Future[T] - def runSyncTx[T](f: => T): Unit -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala b/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala deleted file mode 100644 index d765833..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala +++ /dev/null @@ -1,10 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.domain.Id - -class EntityNotFoundException(id: String, tableName: String) - extends RuntimeException(s"Entity with id $id is not found in $tableName table") { - - def this(id: Id[_], tableName: String) = this(id.toString, tableName) - def this(id: Long, tableName: String) = this(id.toString, tableName) -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala b/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala deleted file mode 100644 index 44f177c..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala +++ /dev/null @@ -1,28 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.logging._ - -import scala.concurrent.Future -import scala.util.{Failure, Success, Try} - -class JdbcDbIo(sqlContext: TransactionalContext) extends DbIo with PhiLogging { - - override def runAsync[T](f: => T): Future[T] = { - Future(f)(sqlContext.executionContext) - } - - override def runAsyncTx[T](f: => T): Future[T] = { - import sqlContext.executionContext - - Future(sqlContext.transaction(f)).andThen { - case Failure(e) => logger.error(phi"Can't run a transaction: $e") - } - } - - override def runSyncTx[T](f: => T): Unit = { - Try(sqlContext.transaction(f)) match { - case Success(_) => - case Failure(e) => logger.error(phi"Can't run a transaction: $e") - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala b/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala deleted file mode 100644 index 92689dd..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala +++ /dev/null @@ -1,19 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.logging._ - -/** - * @param pageNumber Starts with 1 - */ -final case class Pagination(pageSize: Int, pageNumber: Int) - -object Pagination { - - // @see https://driverinc.atlassian.net/wiki/display/RA/REST+API+Specification#RESTAPISpecification-CommonRequestQueryParametersForWebServices - val Default = Pagination(pageSize = 100, pageNumber = 1) - - implicit def toPhiString(x: Pagination): PhiString = { - import x._ - phi"Pagination(pageSize=${Unsafe(pageSize)}, pageNumber=${Unsafe(pageNumber)})" - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala deleted file mode 100644 index 0577921..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala +++ /dev/null @@ -1,208 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.logging._ - -sealed trait SearchFilterExpr { - def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] - def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr -} - -object SearchFilterExpr { - - val Empty = Intersection.Empty - val Forbid = Atom.Binary( - dimension = Dimension(None, "true"), - op = SearchFilterBinaryOperation.Eq, - value = "false" - ) - - final case class Dimension(tableName: Option[String], name: String) { - def isForeign: Boolean = tableName.isDefined - } - - sealed trait Atom extends SearchFilterExpr { - override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { - if (p(this)) Some(this) - else None - } - - override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { - if (f.isDefinedAt(this)) f(this) - else this - } - } - - object Atom { - final case class Binary(dimension: Dimension, op: SearchFilterBinaryOperation, value: AnyRef) extends Atom - object Binary { - def apply(field: String, op: SearchFilterBinaryOperation, value: AnyRef): Binary = - Binary(Dimension(None, field), op, value) - } - - final case class NAry(dimension: Dimension, op: SearchFilterNAryOperation, values: Seq[AnyRef]) extends Atom - object NAry { - def apply(field: String, op: SearchFilterNAryOperation, values: Seq[AnyRef]): NAry = - NAry(Dimension(None, field), op, values) - } - - /** dimension.tableName extractor */ - object TableName { - def unapply(value: Atom): Option[String] = value match { - case Binary(Dimension(tableNameOpt, _), _, _) => tableNameOpt - case NAry(Dimension(tableNameOpt, _), _, _) => tableNameOpt - } - } - } - - final case class Intersection private (operands: Seq[SearchFilterExpr]) - extends SearchFilterExpr with SearchFilterExprSeqOps { - - override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { - if (f.isDefinedAt(this)) f(this) - else { - this.copy(operands.map(_.replace(f))) - } - } - - } - - object Intersection { - - val Empty = Intersection(Seq()) - - def create(operands: SearchFilterExpr*): SearchFilterExpr = { - val filtered = operands.filterNot(SearchFilterExpr.isEmpty) - filtered.size match { - case 0 => Empty - case 1 => filtered.head - case _ => Intersection(filtered) - } - } - } - - final case class Union private (operands: Seq[SearchFilterExpr]) - extends SearchFilterExpr with SearchFilterExprSeqOps { - - override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { - if (f.isDefinedAt(this)) f(this) - else { - this.copy(operands.map(_.replace(f))) - } - } - - } - - object Union { - - val Empty = Union(Seq()) - - def create(operands: SearchFilterExpr*): SearchFilterExpr = { - val filtered = operands.filterNot(SearchFilterExpr.isEmpty) - filtered.size match { - case 0 => Empty - case 1 => filtered.head - case _ => Union(filtered) - } - } - - def create(dimension: Dimension, values: String*): SearchFilterExpr = values.size match { - case 0 => SearchFilterExpr.Empty - case 1 => SearchFilterExpr.Atom.Binary(dimension, SearchFilterBinaryOperation.Eq, values.head) - case _ => - val filters = values.map { value => - SearchFilterExpr.Atom.Binary(dimension, SearchFilterBinaryOperation.Eq, value) - } - - create(filters: _*) - } - - def create(dimension: Dimension, values: Set[String]): SearchFilterExpr = - create(dimension, values.toSeq: _*) - - // Backwards compatible API - - /** Create SearchFilterExpr with empty tableName */ - def create(field: String, values: String*): SearchFilterExpr = - create(Dimension(None, field), values: _*) - - /** Create SearchFilterExpr with empty tableName */ - def create(field: String, values: Set[String]): SearchFilterExpr = - create(Dimension(None, field), values) - } - - case object AllowAll extends SearchFilterExpr { - override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { - if (p(this)) Some(this) - else None - } - - override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { - if (f.isDefinedAt(this)) f(this) - else this - } - } - - case object DenyAll extends SearchFilterExpr { - override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { - if (p(this)) Some(this) - else None - } - - override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { - if (f.isDefinedAt(this)) f(this) - else this - } - } - - def isEmpty(expr: SearchFilterExpr): Boolean = { - expr == Intersection.Empty || expr == Union.Empty - } - - sealed trait SearchFilterExprSeqOps { this: SearchFilterExpr => - - val operands: Seq[SearchFilterExpr] - - override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { - if (p(this)) Some(this) - else { - // Search the first expr among operands, which satisfy p - // Is's ok to use foldLeft. If there will be performance issues, replace it by recursive loop - operands.foldLeft(Option.empty[SearchFilterExpr]) { - case (None, expr) => expr.find(p) - case (x, _) => x - } - } - } - - } - - // There is no case, when this is unsafe. At this time. - implicit def toPhiString(x: SearchFilterExpr): PhiString = { - if (isEmpty(x)) Unsafe("SearchFilterExpr.Empty") - else Unsafe(x.toString) - } - -} - -sealed trait SearchFilterBinaryOperation - -object SearchFilterBinaryOperation { - - case object Eq extends SearchFilterBinaryOperation - case object NotEq extends SearchFilterBinaryOperation - case object Like extends SearchFilterBinaryOperation - case object Gt extends SearchFilterBinaryOperation - case object GtEq extends SearchFilterBinaryOperation - case object Lt extends SearchFilterBinaryOperation - case object LtEq extends SearchFilterBinaryOperation - -} - -sealed trait SearchFilterNAryOperation - -object SearchFilterNAryOperation { - - case object In extends SearchFilterNAryOperation - case object NotIn extends SearchFilterNAryOperation - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SlickPostgresQueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SlickPostgresQueryBuilder.scala deleted file mode 100644 index a56ab9a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/SlickPostgresQueryBuilder.scala +++ /dev/null @@ -1,115 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import java.time.{LocalDateTime, ZoneOffset} - -import slick.jdbc.{JdbcProfile, GetResult} -import xyz.driver.core.database.SlickDal -import xyz.driver.pdsuicommon.logging._ - -import scala.collection.breakOut -import scala.concurrent.ExecutionContext - -object SlickPostgresQueryBuilder extends PhiLogging { - - import xyz.driver.pdsuicommon.db.SlickQueryBuilder._ - - def apply[T](databaseName: String, - tableName: String, - lastUpdateFieldName: Option[String], - nullableFields: Set[String], - links: Set[SlickTableLink], - runner: Runner[T], - countRunner: CountRunner)(implicit sqlContext: SlickDal, - profile: JdbcProfile, - getResult: GetResult[T], - ec: ExecutionContext): SlickPostgresQueryBuilder[T] = { - val parameters = SlickPostgresQueryBuilderParameters( - databaseName = databaseName, - tableData = TableData(tableName, lastUpdateFieldName, nullableFields), - links = links.map(x => x.foreignTableName -> x)(breakOut) - ) - new SlickPostgresQueryBuilder[T](parameters)(runner, countRunner) - } - - def apply[T](databaseName: String, - tableName: String, - lastUpdateFieldName: Option[String], - nullableFields: Set[String], - links: Set[SlickTableLink])(implicit sqlContext: SlickDal, - profile: JdbcProfile, - getResult: GetResult[T], - ec: ExecutionContext): SlickPostgresQueryBuilder[T] = { - apply[T](databaseName, - tableName, - SlickQueryBuilderParameters.AllFields, - lastUpdateFieldName, - nullableFields, - links) - } - - def apply[T](databaseName: String, - tableName: String, - fields: Set[String], - lastUpdateFieldName: Option[String], - nullableFields: Set[String], - links: Set[SlickTableLink])(implicit sqlContext: SlickDal, - profile: JdbcProfile, - getResult: GetResult[T], - ec: ExecutionContext): SlickPostgresQueryBuilder[T] = { - - val runner: Runner[T] = { parameters => - val sql = parameters.toSql(countQuery = false, fields = fields).as[T] - logger.debug(phi"${Unsafe(sql)}") - sqlContext.execute(sql) - } - - val countRunner: CountRunner = { parameters => - implicit val getCountResult: GetResult[(Int, Option[LocalDateTime])] = GetResult({ r => - val count = r.rs.getInt(1) - val lastUpdate = if (parameters.tableData.lastUpdateFieldName.isDefined) { - Option(r.rs.getTimestamp(2)).map(timestampToLocalDateTime) - } else None - (count, lastUpdate) - }) - val sql = parameters.toSql(countQuery = true).as[(Int, Option[LocalDateTime])] - logger.debug(phi"${Unsafe(sql)}") - sqlContext.execute(sql).map(_.head) - } - - apply[T]( - databaseName = databaseName, - tableName = tableName, - lastUpdateFieldName = lastUpdateFieldName, - nullableFields = nullableFields, - links = links, - runner = runner, - countRunner = countRunner - ) - } - - def timestampToLocalDateTime(timestamp: java.sql.Timestamp): LocalDateTime = { - LocalDateTime.ofInstant(timestamp.toInstant, ZoneOffset.UTC) - } -} - -class SlickPostgresQueryBuilder[T](parameters: SlickPostgresQueryBuilderParameters)( - implicit runner: SlickQueryBuilder.Runner[T], - countRunner: SlickQueryBuilder.CountRunner) - extends SlickQueryBuilder[T](parameters) { - - def withFilter(newFilter: SearchFilterExpr): SlickQueryBuilder[T] = { - new SlickPostgresQueryBuilder[T](parameters.copy(filter = newFilter)) - } - - def withSorting(newSorting: Sorting): SlickQueryBuilder[T] = { - new SlickPostgresQueryBuilder[T](parameters.copy(sorting = newSorting)) - } - - def withPagination(newPagination: Pagination): SlickQueryBuilder[T] = { - new SlickPostgresQueryBuilder[T](parameters.copy(pagination = Some(newPagination))) - } - - def resetPagination: SlickQueryBuilder[T] = { - new SlickPostgresQueryBuilder[T](parameters.copy(pagination = None)) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala deleted file mode 100644 index 9962edf..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/SlickQueryBuilder.scala +++ /dev/null @@ -1,387 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import java.sql.{JDBCType, PreparedStatement} -import java.time.LocalDateTime - -import slick.jdbc.{JdbcProfile, PositionedParameters, SQLActionBuilder, SetParameter} -import xyz.driver.pdsuicommon.db.Sorting.{Dimension, Sequential} -import xyz.driver.pdsuicommon.db.SortingOrder.{Ascending, Descending} -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} - -import scala.concurrent.{ExecutionContext, Future} - -object SlickQueryBuilder { - - type Runner[T] = SlickQueryBuilderParameters => Future[Seq[T]] - - type CountResult = Future[(Int, Option[LocalDateTime])] - - type CountRunner = SlickQueryBuilderParameters => CountResult - - /** - * Binder for PreparedStatement - */ - type Binder = PreparedStatement => PreparedStatement - - final case class TableData(tableName: String, - lastUpdateFieldName: Option[String] = None, - nullableFields: Set[String] = Set.empty) - - val AllFields = Set("*") - - implicit class SQLActionBuilderConcat(a: SQLActionBuilder) { - def concat(b: SQLActionBuilder): SQLActionBuilder = { - SQLActionBuilder(a.queryParts ++ b.queryParts, new SetParameter[Unit] { - def apply(p: Unit, pp: PositionedParameters): Unit = { - a.unitPConv.apply(p, pp) - b.unitPConv.apply(p, pp) - } - }) - } - } - - implicit object SetQueryParameter extends SetParameter[AnyRef] { - def apply(v: AnyRef, pp: PositionedParameters) = { - pp.setObject(v, JDBCType.BINARY.getVendorTypeNumber) - } - } - - implicit def setLongIdQueryParameter[T]: SetParameter[LongId[T]] = SetParameter[LongId[T]] { (v, pp) => - pp.setLong(v.id) - } - - implicit def setStringIdQueryParameter[T]: SetParameter[StringId[T]] = SetParameter[StringId[T]] { (v, pp) => - pp.setString(v.id) - } - - implicit def setUuidIdQueryParameter[T]: SetParameter[UuidId[T]] = SetParameter[UuidId[T]] { (v, pp) => - pp.setObject(v.id, JDBCType.BINARY.getVendorTypeNumber) - } -} - -final case class SlickTableLink(keyColumnName: String, foreignTableName: String, foreignKeyColumnName: String) - -object SlickQueryBuilderParameters { - val AllFields = Set("*") -} - -sealed trait SlickQueryBuilderParameters { - import SlickQueryBuilder._ - - def databaseName: String - def tableData: SlickQueryBuilder.TableData - def links: Map[String, SlickTableLink] - def filter: SearchFilterExpr - def sorting: Sorting - def pagination: Option[Pagination] - - def qs: String - - def findLink(tableName: String): SlickTableLink = links.get(tableName) match { - case None => throw new IllegalArgumentException(s"Cannot find a link for `$tableName`") - case Some(link) => link - } - - def toSql(countQuery: Boolean = false)(implicit profile: JdbcProfile): SQLActionBuilder = { - toSql(countQuery, SlickQueryBuilderParameters.AllFields) - } - - def toSql(countQuery: Boolean, fields: Set[String])(implicit profile: JdbcProfile): SQLActionBuilder = { - import profile.api._ - val escapedTableName = s"""$qs$databaseName$qs.$qs${tableData.tableName}$qs""" - val fieldsSql: String = if (countQuery) { - val suffix: String = tableData.lastUpdateFieldName match { - case Some(lastUpdateField) => s", max($escapedTableName.$qs$lastUpdateField$qs)" - case None => "" - } - s"count(*) $suffix" - } else { - if (fields == SlickQueryBuilderParameters.AllFields) { - s"$escapedTableName.*" - } else { - fields - .map { field => - s"$escapedTableName.$qs$field$qs" - } - .mkString(", ") - } - } - val where = filterToSql(escapedTableName, filter) - val orderBy = sortingToSql(escapedTableName, sorting) - - val limitSql = limitToSql() - - val sql = sql"""select #$fieldsSql from #$escapedTableName""" - - val filtersTableLinks: Seq[SlickTableLink] = { - import SearchFilterExpr._ - def aux(expr: SearchFilterExpr): Seq[SlickTableLink] = expr match { - case Atom.TableName(tableName) => List(findLink(tableName)) - case Intersection(xs) => xs.flatMap(aux) - case Union(xs) => xs.flatMap(aux) - case _ => Nil - } - aux(filter) - } - - val sortingTableLinks: Seq[SlickTableLink] = Sorting.collect(sorting) { - case Dimension(Some(foreignTableName), _, _) => findLink(foreignTableName) - } - - // Combine links from sorting and filter without duplicates - val foreignTableLinks = (filtersTableLinks ++ sortingTableLinks).distinct - - def fkSql(fkLinksSql: SQLActionBuilder, tableLinks: Seq[SlickTableLink]): SQLActionBuilder = { - if (tableLinks.nonEmpty) { - tableLinks.head match { - case SlickTableLink(keyColumnName, foreignTableName, foreignKeyColumnName) => - val escapedForeignTableName = s"$qs$databaseName$qs.$qs$foreignTableName$qs" - val join = sql""" inner join #$escapedForeignTableName - on #$escapedTableName.#$qs#$keyColumnName#$qs=#$escapedForeignTableName.#$qs#$foreignKeyColumnName#$qs""" - fkSql(fkLinksSql concat join, tableLinks.tail) - } - } else fkLinksSql - } - val foreignTableLinksSql = fkSql(sql"", foreignTableLinks) - - val whereSql = if (where.queryParts.size > 1) { - sql" where " concat where - } else sql"" - - val orderSql = if (orderBy.nonEmpty && !countQuery) { - sql" order by #$orderBy" - } else sql"" - - val limSql = if (limitSql.queryParts.size > 1 && !countQuery) { - sql" " concat limitSql - } else sql"" - - sql concat foreignTableLinksSql concat whereSql concat orderSql concat limSql - } - - /** - * Converts filter expression to SQL expression. - * - * @return Returns SQL string and list of values for binding in prepared statement. - */ - protected def filterToSql(escapedTableName: String, filter: SearchFilterExpr)( - implicit profile: JdbcProfile): SQLActionBuilder = { - import SearchFilterBinaryOperation._ - import SearchFilterExpr._ - import profile.api._ - - def isNull(string: AnyRef) = Option(string).isEmpty || string.toString.toLowerCase == "null" - - def escapeDimension(dimension: SearchFilterExpr.Dimension) = { - s"${dimension.tableName.map(t => s"$qs$databaseName$qs.$qs$t$qs").getOrElse(escapedTableName)}.$qs${dimension.name}$qs" - } - - def filterToSqlMultiple(operands: Seq[SearchFilterExpr]) = operands.collect { - case x if !SearchFilterExpr.isEmpty(x) => filterToSql(escapedTableName, x) - } - - def multipleSqlToAction(first: Boolean, - op: String, - conditions: Seq[SQLActionBuilder], - sql: SQLActionBuilder): SQLActionBuilder = { - if (conditions.nonEmpty) { - val condition = conditions.head - if (first) { - multipleSqlToAction(first = false, op, conditions.tail, condition) - } else { - multipleSqlToAction(first = false, op, conditions.tail, sql concat sql" #${op} " concat condition) - } - } else sql - } - - def concatenateParameters(sql: SQLActionBuilder, first: Boolean, tail: Seq[AnyRef]): SQLActionBuilder = { - if (tail.nonEmpty) { - if (!first) { - concatenateParameters(sql concat sql""",${tail.head}""", first = false, tail.tail) - } else { - concatenateParameters(sql"""(${tail.head}""", first = false, tail.tail) - } - } else sql concat sql")" - } - - filter match { - case x if isEmpty(x) => - sql"" - - case AllowAll => - sql"1=1" - - case DenyAll => - sql"1=0" - - case Atom.Binary(dimension, Eq, value) if isNull(value) => - sql"#${escapeDimension(dimension)} is NULL" - - case Atom.Binary(dimension, NotEq, value) if isNull(value) => - sql"#${escapeDimension(dimension)} is not NULL" - - case Atom.Binary(dimension, NotEq, value) if tableData.nullableFields.contains(dimension.name) => - // In MySQL NULL <> Any === NULL - // So, to handle NotEq for nullable fields we need to use more complex SQL expression. - // http://dev.mysql.com/doc/refman/5.7/en/working-with-null.html - val escapedColumn = escapeDimension(dimension) - sql"(#${escapedColumn} is null or #${escapedColumn} != $value)" - - case Atom.Binary(dimension, op, value) => - val operator = op match { - case Eq => sql"=" - case NotEq => sql"!=" - case Like => sql" like " - case Gt => sql">" - case GtEq => sql">=" - case Lt => sql"<" - case LtEq => sql"<=" - } - sql"#${escapeDimension(dimension)}" concat operator concat sql"""$value""" - - case Atom.NAry(dimension, op, values) => - val sqlOp = op match { - case SearchFilterNAryOperation.In => sql" in " - case SearchFilterNAryOperation.NotIn => sql" not in " - } - - if (values.nonEmpty) { - val formattedValues = concatenateParameters(sql"", first = true, values) - sql"#${escapeDimension(dimension)}" concat sqlOp concat formattedValues - } else { - sql"1=0" - } - - case Intersection(operands) => - val filter = multipleSqlToAction(first = true, "and", filterToSqlMultiple(operands), sql"") - sql"(" concat filter concat sql")" - - case Union(operands) => - val filter = multipleSqlToAction(first = true, "or", filterToSqlMultiple(operands), sql"") - sql"(" concat filter concat sql")" - } - } - - protected def limitToSql()(implicit profile: JdbcProfile): SQLActionBuilder - - /** - * @param escapedMainTableName Should be escaped - */ - protected def sortingToSql(escapedMainTableName: String, sorting: Sorting)(implicit profile: JdbcProfile): String = { - sorting match { - case Dimension(optSortingTableName, field, order) => - val sortingTableName = - optSortingTableName.map(x => s"$qs$databaseName$qs.$qs$x$qs").getOrElse(escapedMainTableName) - val fullName = s"$sortingTableName.$qs$field$qs" - - s"$fullName ${orderToSql(order)}" - - case Sequential(xs) => - xs.map(sortingToSql(escapedMainTableName, _)).mkString(", ") - } - } - - protected def orderToSql(x: SortingOrder): String = x match { - case Ascending => "asc" - case Descending => "desc" - } - - protected def binder(bindings: List[AnyRef])(bind: PreparedStatement): PreparedStatement = { - bindings.zipWithIndex.foreach { - case (binding, index) => - bind.setObject(index + 1, binding) - } - - bind - } - -} - -final case class SlickPostgresQueryBuilderParameters(databaseName: String, - tableData: SlickQueryBuilder.TableData, - links: Map[String, SlickTableLink] = Map.empty, - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Sorting = Sorting.Empty, - pagination: Option[Pagination] = None) - extends SlickQueryBuilderParameters { - - def limitToSql()(implicit profile: JdbcProfile): SQLActionBuilder = { - import profile.api._ - pagination.map { pagination => - val startFrom = (pagination.pageNumber - 1) * pagination.pageSize - sql"limit #${pagination.pageSize} OFFSET #$startFrom" - } getOrElse (sql"") - } - - val qs = """"""" - -} - -/** - * @param links Links to another tables grouped by foreignTableName - */ -final case class SlickMysqlQueryBuilderParameters(databaseName: String, - tableData: SlickQueryBuilder.TableData, - links: Map[String, SlickTableLink] = Map.empty, - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Sorting = Sorting.Empty, - pagination: Option[Pagination] = None) - extends SlickQueryBuilderParameters { - - def limitToSql()(implicit profile: JdbcProfile): SQLActionBuilder = { - import profile.api._ - pagination - .map { pagination => - val startFrom = (pagination.pageNumber - 1) * pagination.pageSize - sql"limit #$startFrom, #${pagination.pageSize}" - } - .getOrElse(sql"") - } - - val qs = """`""" - -} - -abstract class SlickQueryBuilder[T](val parameters: SlickQueryBuilderParameters)( - implicit runner: SlickQueryBuilder.Runner[T], - countRunner: SlickQueryBuilder.CountRunner) { - - def run()(implicit ec: ExecutionContext): Future[Seq[T]] = runner(parameters) - - def runCount()(implicit ec: ExecutionContext): SlickQueryBuilder.CountResult = countRunner(parameters) - - /** - * Runs the query and returns total found rows without considering of pagination. - */ - def runWithCount()(implicit ec: ExecutionContext): Future[(Seq[T], Int, Option[LocalDateTime])] = { - for { - all <- run - (total, lastUpdate) <- runCount - } yield (all, total, lastUpdate) - } - - def withFilter(newFilter: SearchFilterExpr): SlickQueryBuilder[T] - - def withFilter(filter: Option[SearchFilterExpr]): SlickQueryBuilder[T] = { - filter.fold(this)(withFilter) - } - - def resetFilter: SlickQueryBuilder[T] = withFilter(SearchFilterExpr.Empty) - - def withSorting(newSorting: Sorting): SlickQueryBuilder[T] - - def withSorting(sorting: Option[Sorting]): SlickQueryBuilder[T] = { - sorting.fold(this)(withSorting) - } - - def resetSorting: SlickQueryBuilder[T] = withSorting(Sorting.Empty) - - def withPagination(newPagination: Pagination): SlickQueryBuilder[T] - - def withPagination(pagination: Option[Pagination]): SlickQueryBuilder[T] = { - pagination.fold(this)(withPagination) - } - - def resetPagination: SlickQueryBuilder[T] - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala b/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala deleted file mode 100644 index 8adf629..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala +++ /dev/null @@ -1,61 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.logging._ - -import scala.collection.generic.CanBuildFrom - -sealed trait SortingOrder -object SortingOrder { - - case object Ascending extends SortingOrder - case object Descending extends SortingOrder - -} - -sealed trait Sorting - -object Sorting { - - val Empty = Sequential(Seq.empty) - - /** - * @param tableName None if the table is default (same) - * @param name Dimension name - * @param order Order - */ - final case class Dimension(tableName: Option[String], name: String, order: SortingOrder) extends Sorting { - def isForeign: Boolean = tableName.isDefined - } - - final case class Sequential(sorting: Seq[Dimension]) extends Sorting { - override def toString: String = if (isEmpty(this)) "Empty" else super.toString - } - - def isEmpty(input: Sorting): Boolean = { - input match { - case Sequential(Seq()) => true - case _ => false - } - } - - def filter(sorting: Sorting, p: Dimension => Boolean): Seq[Dimension] = sorting match { - case x: Dimension if p(x) => Seq(x) - case _: Dimension => Seq.empty - case Sequential(xs) => xs.filter(p) - } - - def collect[B, That](sorting: Sorting)(f: PartialFunction[Dimension, B])( - implicit bf: CanBuildFrom[Seq[Dimension], B, That]): That = sorting match { - case x: Dimension if f.isDefinedAt(x) => - val r = bf.apply() - r += f(x) - r.result() - - case _: Dimension => bf.apply().result() - case Sequential(xs) => xs.collect(f) - } - - // Contains dimensions and ordering only, thus it is safe. - implicit def toPhiString(x: Sorting): PhiString = Unsafe(x.toString) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala b/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala deleted file mode 100644 index 9883b9e..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala +++ /dev/null @@ -1,11 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import scala.concurrent.ExecutionContext - -trait TransactionalContext { - - implicit def executionContext: ExecutionContext - - def transaction[T](f: => T): T - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/Repository.scala b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/Repository.scala deleted file mode 100644 index e62238e..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/Repository.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.pdsuicommon.db.repositories - -trait Repository extends RepositoryLogging diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/RepositoryLogging.scala b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/RepositoryLogging.scala deleted file mode 100644 index d1ec1da..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/RepositoryLogging.scala +++ /dev/null @@ -1,62 +0,0 @@ -package xyz.driver.pdsuicommon.db.repositories - -import xyz.driver.pdsuicommon.logging._ - -trait RepositoryLogging extends PhiLogging { - - protected def logCreatedOne[T](x: T)(implicit toPhiString: T => PhiString): T = { - logger.info(phi"An entity was created: $x") - x - } - - protected def logCreatedMultiple[T <: Iterable[_]](xs: T)(implicit toPhiString: T => PhiString): T = { - if (xs.nonEmpty) { - logger.info(phi"Entities were created: $xs") - } - xs - } - - protected def logUpdatedOne(rowsAffected: Long): Long = { - rowsAffected match { - case 0 => logger.trace(phi"The entity is up to date") - case 1 => logger.info(phi"The entity was updated") - case x => logger.warn(phi"The ${Unsafe(x)} entities were updated") - } - rowsAffected - } - - protected def logUpdatedOneUnimportant(rowsAffected: Long): Long = { - rowsAffected match { - case 0 => logger.trace(phi"The entity is up to date") - case 1 => logger.trace(phi"The entity was updated") - case x => logger.warn(phi"The ${Unsafe(x)} entities were updated") - } - rowsAffected - } - - protected def logUpdatedMultiple(rowsAffected: Long): Long = { - rowsAffected match { - case 0 => logger.trace(phi"All entities are up to date") - case x => logger.info(phi"The ${Unsafe(x)} entities were updated") - } - rowsAffected - } - - protected def logDeletedOne(rowsAffected: Long): Long = { - rowsAffected match { - case 0 => logger.trace(phi"The entity does not exist") - case 1 => logger.info(phi"The entity was deleted") - case x => logger.warn(phi"Deleted ${Unsafe(x)} entities, expected one") - } - rowsAffected - } - - protected def logDeletedMultiple(rowsAffected: Long): Long = { - rowsAffected match { - case 0 => logger.trace(phi"Entities do not exist") - case x => logger.info(phi"Deleted ${Unsafe(x)} entities") - } - rowsAffected - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala deleted file mode 100644 index e238245..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala +++ /dev/null @@ -1,51 +0,0 @@ -package xyz.driver.pdsuicommon.domain - -import java.util.UUID - -import xyz.driver.pdsuicommon.logging._ - -sealed trait Id[+T] - -final case class CompoundId[Id1 <: Id[_], Id2 <: Id[_]](part1: Id1, part2: Id2) extends Id[(Id1, Id2)] - -final case class LongId[+T](id: Long) extends Id[T] { - override def toString: String = id.toString - - def is(longId: Long): Boolean = { - id == longId - } -} - -object LongId { - implicit def toPhiString[T](x: LongId[T]): PhiString = Unsafe(s"LongId(${x.id})") -} - -final case class StringId[+T](id: String) extends Id[T] { - override def toString: String = id - - def is(stringId: String): Boolean = { - id == stringId - } -} - -object StringId { - implicit def toPhiString[T](x: StringId[T]): PhiString = Unsafe(s"StringId(${x.id})") -} - -final case class UuidId[+T](id: UUID) extends Id[T] { - override def toString: String = id.toString -} - -object UuidId { - - /** - * @note May fail, if `string` is invalid UUID. - */ - def apply[T](string: String): UuidId[T] = new UuidId[T](UUID.fromString(string)) - - def apply[T](): UuidId[T] = new UuidId[T](UUID.randomUUID()) - - implicit def ordering[T] = Ordering.by[UuidId[T], String](_.toString) - - implicit def toPhiString[T](x: UuidId[T]): PhiString = Unsafe(s"UuidId(${x.id})") -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala deleted file mode 100644 index ee4d884..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala +++ /dev/null @@ -1,14 +0,0 @@ -package xyz.driver.pdsuicommon.domain - -import xyz.driver.pdsuicommon.logging._ - -final case class TextJson[+T](content: T) { - def map[U](f: T => U): TextJson[U] = copy(f(content)) -} - -object TextJson { - - implicit def toPhiString[T](x: TextJson[T])(implicit inner: T => PhiString): PhiString = { - phi"TextJson(${x.content})" - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala b/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala deleted file mode 100644 index becb585..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala +++ /dev/null @@ -1,27 +0,0 @@ -package xyz.driver.pdsuicommon.error - -import xyz.driver.pdsuicommon.logging.{PhiString, Unsafe} -import xyz.driver.pdsuicommon.utils.Utils - -trait DomainError { - - protected def userMessage: String - - def getMessage: String = userMessage - -} - -object DomainError { - - // 404 error - trait NotFoundError extends DomainError - - // 403 error - trait AuthorizationError extends DomainError - - implicit def toPhiString(x: DomainError): PhiString = { - // userMessage possibly can contain a personal information, - // so we should prevent it to be printed in logs. - Unsafe(Utils.getClassSimpleName(x.getClass)) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/ErrorCode.scala b/src/main/scala/xyz/driver/pdsuicommon/error/ErrorCode.scala deleted file mode 100644 index 748e76a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/ErrorCode.scala +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.driver.pdsuicommon.error - -import xyz.driver.core.json.EnumJsonFormat - -@SuppressWarnings(Array("org.wartremover.warts.Enumeration")) -object ErrorCode extends Enumeration { - - type ErrorCode = Value - val Unspecified = Value(1) - - implicit val jsonFormat = new EnumJsonFormat[ErrorCode]( - "200" -> ErrorCode.Value(200), - "400" -> ErrorCode.Value(400), - "401" -> ErrorCode.Value(401), - "403" -> ErrorCode.Value(403), - "404" -> ErrorCode.Value(404), - "500" -> ErrorCode.Value(500) - ) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala b/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala deleted file mode 100644 index 4d6aa0b..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/ErrorsResponse.scala +++ /dev/null @@ -1,52 +0,0 @@ -package xyz.driver.pdsuicommon.error - -import spray.json._ -import ErrorsResponse.ResponseError - -final case class ErrorsResponse(errors: Seq[ResponseError], requestId: String) - -object ErrorsResponse { - import DefaultJsonProtocol._ - - /** - * @param data Any data that can be associated with particular error.Ex.: error field name - * @param message Error message - * @param code Unique error code - * - * @see https://driverinc.atlassian.net/wiki/display/RA/REST+API+Specification#RESTAPISpecification-HTTPStatuscodes - */ - final case class ResponseError(data: Option[String], message: String, code: Int) - - object ResponseError { - - implicit val responseErrorJsonFormat: RootJsonFormat[ResponseError] = jsonFormat3(ResponseError.apply) - - } - - implicit val errorsResponseJsonFormat: RootJsonFormat[ErrorsResponse] = new RootJsonFormat[ErrorsResponse] { - override def write(obj: ErrorsResponse): JsValue = { - JsObject( - "errors" -> obj.errors.map(_.toJson).toJson, - "requestId" -> obj.requestId.toJson - ) - } - - override def read(json: JsValue): ErrorsResponse = json match { - case JsObject(fields) => - val errors = fields - .get("errors") - .map(_.convertTo[Seq[ResponseError]]) - .getOrElse(deserializationError(s"ErrorsResponse json object does not contain `errors` field: $json")) - - val requestId = fields - .get("requestId") - .map(id => id.convertTo[String]) - .getOrElse(deserializationError(s"ErrorsResponse json object does not contain `requestId` field: $json")) - - ErrorsResponse(errors, requestId) - - case _ => deserializationError(s"Expected json as ErrorsResponse, but got $json") - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/ExceptionFormatter.scala b/src/main/scala/xyz/driver/pdsuicommon/error/ExceptionFormatter.scala deleted file mode 100644 index c9578b3..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/ExceptionFormatter.scala +++ /dev/null @@ -1,18 +0,0 @@ -package xyz.driver.pdsuicommon.error - -import java.io.{ByteArrayOutputStream, PrintStream} - -object ExceptionFormatter { - - def format(e: Throwable): String = s"$e\n${printStackTrace(e)}" - - def printStackTrace(e: Throwable): String = { - val baos = new ByteArrayOutputStream() - val ps = new PrintStream(baos) - - e.printStackTrace(ps) - - ps.close() - baos.toString() - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/FailedValidationException.scala b/src/main/scala/xyz/driver/pdsuicommon/error/FailedValidationException.scala deleted file mode 100644 index 7137255..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/FailedValidationException.scala +++ /dev/null @@ -1,5 +0,0 @@ -package xyz.driver.pdsuicommon.error - -import xyz.driver.pdsuicommon.validation.ValidationError - -class FailedValidationException(val error: ValidationError) extends RuntimeException("The validation is failed") diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/IncorrectIdException.scala b/src/main/scala/xyz/driver/pdsuicommon/error/IncorrectIdException.scala deleted file mode 100644 index 5705229..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/error/IncorrectIdException.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.pdsuicommon.error - -final case class IncorrectIdException(message: String) extends Exception(message) diff --git a/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala b/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala deleted file mode 100644 index 085dcd8..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala +++ /dev/null @@ -1,90 +0,0 @@ -package xyz.driver.pdsuicommon.http - -import java.io.Closeable -import java.net.URL -import java.util.concurrent.{ExecutorService, Executors} - -import com.typesafe.scalalogging.StrictLogging -import org.asynchttpclient._ -import org.slf4j.MDC -import xyz.driver.pdsuicommon.concurrent.MdcThreadFactory -import xyz.driver.pdsuicommon.utils.RandomUtils - -import scala.concurrent.duration.FiniteDuration -import scala.concurrent.{ExecutionContext, Future, Promise} - -class AsyncHttpClientFetcher(settings: AsyncHttpClientFetcher.Settings) - extends HttpFetcher with Closeable with StrictLogging { - - private val es: ExecutorService = { - val threadFactory = MdcThreadFactory.from(Executors.defaultThreadFactory()) - Executors.newSingleThreadExecutor(threadFactory) - } - - private implicit val executionContext = ExecutionContext.fromExecutor(es) - - private def httpClientConfig: DefaultAsyncHttpClientConfig = { - val builder = new DefaultAsyncHttpClientConfig.Builder() - builder.setConnectTimeout(settings.connectTimeout.toMillis.toInt) - builder.setReadTimeout(settings.readTimeout.toMillis.toInt) - // builder.setThreadFactory(threadFactory) // Doesn't help to push MDC context into AsyncCompletionHandler - builder.build() - } - - private val httpClient = new DefaultAsyncHttpClient(httpClientConfig) - - override def apply(url: URL): Future[Array[Byte]] = { - val fingerPrint = RandomUtils.randomString(10) - - // log all outcome connections - logger.info("{}, apply({})", fingerPrint, url) - val promise = Promise[Response]() - - httpClient - .prepareGet(url.toString) - .execute(new AsyncCompletionHandler[Response] { - override def onCompleted(response: Response): Response = { - promise.success(response) - response - } - - override def onThrowable(t: Throwable): Unit = { - promise.failure(t) - super.onThrowable(t) - } - }) - - // Promises have their own ExecutionContext - // So, we have to hack it. - val parentMdcContext = MDC.getCopyOfContextMap - promise.future.flatMap { response => - setContextMap(parentMdcContext) - - if (response.getStatusCode == 200) { - // DO NOT LOG body, it could be PHI - val bytes = response.getResponseBodyAsBytes - logger.debug("{}, size is {}B", fingerPrint, bytes.size.asInstanceOf[AnyRef]) - Future.successful(bytes) - } else { - logger.error("{}, HTTP {}", fingerPrint, response.getStatusCode.asInstanceOf[AnyRef]) - logger.trace(response.getResponseBody().take(100)) - Future.failed(new IllegalStateException("An unexpected response from the server")) - } - } - } - - private[this] def setContextMap(context: java.util.Map[String, String]): Unit = - Option(context).fold(MDC.clear())(MDC.setContextMap) - - override def close(): Unit = { - httpClient.close() - es.shutdown() - } - -} - -object AsyncHttpClientFetcher { - - final case class Settings(connectTimeout: FiniteDuration, readTimeout: FiniteDuration) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientUploader.scala b/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientUploader.scala deleted file mode 100644 index d7bc3d3..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientUploader.scala +++ /dev/null @@ -1,115 +0,0 @@ -package xyz.driver.pdsuicommon.http - -import java.io.Closeable -import java.net.URI -import java.util.concurrent.{ExecutorService, Executors} - -import xyz.driver.pdsuicommon.concurrent.MdcThreadFactory -import xyz.driver.pdsuicommon.http.AsyncHttpClientUploader._ -import xyz.driver.pdsuicommon.utils.RandomUtils -import com.typesafe.scalalogging.StrictLogging -import org.asynchttpclient._ -import org.slf4j.MDC - -import scala.concurrent.duration.FiniteDuration -import scala.concurrent.{ExecutionContext, Future, Promise} - -class AsyncHttpClientUploader(settings: Settings) extends Closeable with StrictLogging { - - private val es: ExecutorService = { - val threadFactory = MdcThreadFactory.from(Executors.defaultThreadFactory()) - Executors.newSingleThreadExecutor(threadFactory) - } - - private implicit val executionContext = ExecutionContext.fromExecutor(es) - - private def httpClientConfig: DefaultAsyncHttpClientConfig = { - val builder = new DefaultAsyncHttpClientConfig.Builder() - builder.setConnectTimeout(settings.connectTimeout.toMillis.toInt) - builder.setRequestTimeout(settings.requestTimeout.toMillis.toInt) - // builder.setThreadFactory(threadFactory) // Doesn't help to push MDC context into AsyncCompletionHandler - builder.build() - } - - private val httpClient = new DefaultAsyncHttpClient(httpClientConfig) - - def run(method: Method, uri: URI, contentType: String, data: String): Future[Unit] = { - // log all outcome connections - val fingerPrint = RandomUtils.randomString(10) - logger.info("{}, apply(method={}, uri={}, contentType={})", fingerPrint, method, uri, contentType) - val promise = Promise[Response]() - - val q = new RequestBuilder(method.toString) - .setUrl(uri.toString) - .setBody(data) - - settings.defaultHeaders.foreach { - case (k, v) => - q.setHeader(k, v) - } - - q.addHeader("Content-Type", contentType) - - httpClient - .prepareRequest(q) - .execute(new AsyncCompletionHandler[Unit] { - override def onCompleted(response: Response): Unit = { - promise.success(response) - } - - override def onThrowable(t: Throwable): Unit = { - promise.failure(t) - super.onThrowable(t) - } - }) - - // see AsyncHttpClientFetcher - val parentMdcContext = MDC.getCopyOfContextMap - promise.future.flatMap { response => - setContextMap(parentMdcContext) - - val statusCode = response.getStatusCode - // https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success - if (statusCode >= 200 && statusCode < 300) { - logger.debug("{}, success", fingerPrint) - Future.successful(()) - } else { - logger.error( - "{}, HTTP {}, BODY:\n{}", - fingerPrint, - response.getStatusCode.asInstanceOf[AnyRef], - response.getResponseBody.take(100) - ) - Future.failed(new IllegalStateException("An unexpected response from the server")) - } - } - } - - private[this] def setContextMap(context: java.util.Map[String, String]): Unit = - Option(context).fold(MDC.clear())(MDC.setContextMap) - - override def close(): Unit = { - httpClient.close() - es.shutdown() - } -} - -object AsyncHttpClientUploader { - - final case class Settings(connectTimeout: FiniteDuration, - requestTimeout: FiniteDuration, - defaultHeaders: Map[String, String] = Map.empty) - - sealed trait Method - - object Method { - - case object Put extends Method { - override val toString = "PUT" - } - - case object Post extends Method { - override val toString = "POST" - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala b/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala deleted file mode 100644 index 46b86a6..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/http/Directives.scala +++ /dev/null @@ -1,114 +0,0 @@ -package xyz.driver.pdsuicommon.http - -import akka.http.scaladsl.server._ -import akka.http.scaladsl.server.Directives._ -import akka.http.scaladsl.model._ -import xyz.driver.core.app.DriverApp -import xyz.driver.pdsuicommon.error._ -import xyz.driver.pdsuicommon.error.DomainError._ -import xyz.driver.pdsuicommon.error.ErrorsResponse.ResponseError -import xyz.driver.pdsuicommon.parsers._ -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain._ -import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ -import xyz.driver.core.generators -import xyz.driver.core.rest.ContextHeaders -import xyz.driver.core.rest.errors.{InvalidActionException, InvalidInputException, ResourceNotFoundException} - -import scala.util.control._ -import scala.util._ - -trait Directives { - - val paginated: Directive1[Pagination] = parameterSeq.flatMap { params => - PaginationParser.parse(params) match { - case Success(pagination) => provide(pagination) - case Failure(ex) => - reject(ValidationRejection("invalid pagination parameter", Some(ex))) - } - } - - def sorted(validDimensions: Set[String] = Set.empty): Directive1[Sorting] = parameterSeq.flatMap { params => - SortingParser.parse(validDimensions, params) match { - case Success(sorting) => provide(sorting) - case Failure(ex) => - reject(ValidationRejection("invalid sorting parameter", Some(ex))) - } - } - - val dimensioned: Directive1[Dimensions] = parameterSeq.flatMap { params => - DimensionsParser.tryParse(params) match { - case Success(dims) => provide(dims) - case Failure(ex) => - reject(ValidationRejection("invalid dimension parameter", Some(ex))) - } - } - - val searchFiltered: Directive1[SearchFilterExpr] = parameterSeq.flatMap { params => - SearchFilterParser.parse(params) match { - case Success(sorting) => provide(sorting) - case Failure(ex) => - reject(ValidationRejection("invalid filter parameter", Some(ex))) - } - } - - def StringIdInPath[T]: PathMatcher1[StringId[T]] = - PathMatchers.Segment.map((id) => StringId(id.toString)) - - def LongIdInPath[T]: PathMatcher1[LongId[T]] = - PathMatchers.LongNumber.map((id) => LongId(id)) - - def UuidIdInPath[T]: PathMatcher1[UuidId[T]] = - PathMatchers.JavaUUID.map((id) => UuidId(id)) - - def failFast[A](reply: A): A = reply match { - case err: NotFoundError => throw ResourceNotFoundException(err.getMessage) - case err: AuthorizationError => throw InvalidActionException(err.getMessage) - case err: DomainError => throw InvalidInputException(err.getMessage) - case other => other - } - - def domainExceptionHandler(req: String): ExceptionHandler = { - def errorResponse(msg: String, code: Int) = - ErrorsResponse(Seq(ResponseError(None, msg, code)), req) - ExceptionHandler { - case ex: InvalidActionException => - complete(StatusCodes.Forbidden -> errorResponse(ex.message, 403)) - - case ex: ResourceNotFoundException => - complete(StatusCodes.NotFound -> errorResponse(ex.message, 404)) - - case ex: InvalidInputException => - complete(StatusCodes.BadRequest -> errorResponse(ex.message, 400)) - - case NonFatal(ex) => - complete(StatusCodes.InternalServerError -> errorResponse(ex.getMessage, 500)) - } - } - - def domainRejectionHandler(req: String): RejectionHandler = { - def wrapContent(message: String) = { - import ErrorsResponse._ - val err: ErrorsResponse = ErrorsResponse(Seq(ResponseError(None, message, 1)), req) - val text = errorsResponseJsonFormat.write(err).toString() - HttpEntity(ContentTypes.`application/json`, text) - } - DriverApp.rejectionHandler.mapRejectionResponse { - case res @ HttpResponse(_, _, ent: HttpEntity.Strict, _) => - res.copy(entity = wrapContent(ent.data.utf8String)) - case x => x // pass through all other types of responses - } - } - - val tracked: Directive1[String] = optionalHeaderValueByName(ContextHeaders.TrackingIdHeader) flatMap { - case Some(id) => provide(id) - case None => provide(generators.nextUuid().toString) - } - - val domainResponse: Directive0 = tracked.flatMap { id => - handleExceptions(domainExceptionHandler(id)) & handleRejections(domainRejectionHandler(id)) - } - -} - -object Directives extends Directives diff --git a/src/main/scala/xyz/driver/pdsuicommon/http/package.scala b/src/main/scala/xyz/driver/pdsuicommon/http/package.scala deleted file mode 100644 index 20b1c97..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/http/package.scala +++ /dev/null @@ -1,9 +0,0 @@ -package xyz.driver.pdsuicommon - -import java.net.URL - -import scala.concurrent.Future - -package object http { - type HttpFetcher = URL => Future[Array[Byte]] -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/json/JsonSerializer.scala b/src/main/scala/xyz/driver/pdsuicommon/json/JsonSerializer.scala deleted file mode 100644 index 9383a1c..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/json/JsonSerializer.scala +++ /dev/null @@ -1,27 +0,0 @@ -package xyz.driver.pdsuicommon.json - -import java.text.SimpleDateFormat - -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.databind.{DeserializationFeature, ObjectMapper} -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule -import com.fasterxml.jackson.module.scala.DefaultScalaModule -import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper - -object JsonSerializer { - - private val mapper = new ObjectMapper() with ScalaObjectMapper - mapper.registerModule(DefaultScalaModule) - mapper.registerModule(new JavaTimeModule) - mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")) - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL) - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - - def serialize(value: Any): String = { - mapper.writeValueAsString(value) - } - - def deserialize[T](value: String)(implicit m: Manifest[T]): T = { - mapper.readValue(value) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/DefaultPhiLogger.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/DefaultPhiLogger.scala deleted file mode 100644 index 045f37a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/DefaultPhiLogger.scala +++ /dev/null @@ -1,17 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -import org.slf4j.{Logger => Underlying} - -class DefaultPhiLogger private[logging] (underlying: Underlying) extends PhiLogger { - - def error(message: PhiString): Unit = underlying.error(message.text) - - def warn(message: PhiString): Unit = underlying.warn(message.text) - - def info(message: PhiString): Unit = underlying.info(message.text) - - def debug(message: PhiString): Unit = underlying.debug(message.text) - - def trace(message: PhiString): Unit = underlying.trace(message.text) - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/Implicits.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/Implicits.scala deleted file mode 100644 index 109d52a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/Implicits.scala +++ /dev/null @@ -1,62 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -import java.io.File -import java.net.{URI, URL} -import java.nio.file.Path -import java.time.{LocalDate, LocalDateTime} -import java.util.UUID - -import scala.concurrent.duration.Duration - -trait Implicits { - - // DO NOT ADD! - // phi"$fullName" is easier to write, than phi"${Unsafe(fullName)}" - // If you wrote the second version, it means that you know, what you doing. - // implicit def toPhiString(s: String): PhiString = Unsafe(s) - - implicit def toPhiStringContext(sc: StringContext): PhiStringContext = new PhiStringContext(sc) - - implicit def booleanToPhiString(x: Boolean): PhiString = Unsafe(x.toString) - - implicit def uriToPhiString(x: URI): PhiString = Unsafe(x.toString) - - implicit def urlToPhiString(x: URL): PhiString = Unsafe(x.toString) - - implicit def pathToPhiString(x: Path): PhiString = Unsafe(x.toString) - - implicit def fileToPhiString(x: File): PhiString = Unsafe(x.toString) - - implicit def localDateTimeToPhiString(x: LocalDateTime): PhiString = Unsafe(x.toString) - - implicit def localDateToPhiString(x: LocalDate): PhiString = Unsafe(x.toString) - - implicit def durationToPhiString(x: Duration): PhiString = Unsafe(x.toString) - - implicit def uuidToPhiString(x: UUID): PhiString = Unsafe(x.toString) - - implicit def tuple2ToPhiString[T1, T2](x: (T1, T2))(implicit inner1: T1 => PhiString, - inner2: T2 => PhiString): PhiString = x match { - case (a, b) => phi"($a, $b)" - } - - implicit def tuple3ToPhiString[T1, T2, T3](x: (T1, T2, T3))(implicit inner1: T1 => PhiString, - inner2: T2 => PhiString, - inner3: T3 => PhiString): PhiString = x match { - case (a, b, c) => phi"($a, $b, $c)" - } - - implicit def optionToPhiString[T](opt: Option[T])(implicit inner: T => PhiString): PhiString = opt match { - case None => phi"None" - case Some(x) => phi"Some($x)" - } - - implicit def iterableToPhiString[T](xs: Iterable[T])(implicit inner: T => PhiString): PhiString = { - Unsafe(xs.map(inner(_).text).mkString("Col(", ", ", ")")) - } - - implicit def throwableToPhiString(x: Throwable): PhiString = { - Unsafe(Option(x.getMessage).getOrElse(x.getClass.getName)) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogger.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogger.scala deleted file mode 100644 index 741ef18..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogger.scala +++ /dev/null @@ -1,15 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -trait PhiLogger { - - def error(message: PhiString): Unit - - def warn(message: PhiString): Unit - - def info(message: PhiString): Unit - - def debug(message: PhiString): Unit - - def trace(message: PhiString): Unit - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogging.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogging.scala deleted file mode 100644 index e7730ea..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogging.scala +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -import org.slf4j.LoggerFactory - -trait PhiLogging extends Implicits { - - protected val logger: PhiLogger = new DefaultPhiLogger(LoggerFactory.getLogger(getClass.getName)) - - /** - * Logs the failMessage on an error level, if isSuccessful is false. - * @return isSuccessful - */ - protected def loggedError(isSuccessful: Boolean, failMessage: PhiString): Boolean = { - if (!isSuccessful) { - logger.error(failMessage) - } - isSuccessful - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiString.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiString.scala deleted file mode 100644 index 78ac62e..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiString.scala +++ /dev/null @@ -1,6 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -class PhiString(private[logging] val text: String) { - // scalastyle:off - @inline def +(that: PhiString) = new PhiString(this.text + that.text) -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiStringContext.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiStringContext.scala deleted file mode 100644 index 97819de..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/PhiStringContext.scala +++ /dev/null @@ -1,8 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -final class PhiStringContext(val sc: StringContext) extends AnyVal { - def phi(args: PhiString*): PhiString = { - val phiArgs = args.map(_.text) - new PhiString(sc.s(phiArgs: _*)) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/TimeLogger.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/TimeLogger.scala deleted file mode 100644 index fbd17eb..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/TimeLogger.scala +++ /dev/null @@ -1,13 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -import java.time.{LocalDateTime, ZoneId} - -import xyz.driver.core.auth.User - -object TimeLogger extends PhiLogging { - - def logTime(userId: xyz.driver.core.Id[User], label: String, obj: String): Unit = { - val now = LocalDateTime.now(ZoneId.of("Z")) - logger.info(phi"User id=${Unsafe(userId)} performed an action at ${Unsafe(label)}=$now with a ${Unsafe(obj)} ") - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala deleted file mode 100644 index c3ebe80..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala +++ /dev/null @@ -1,7 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -/** - * Use it with care! - */ -final case class Unsafe[T](private[logging] val value: T) - extends PhiString(Option(value).map(_.toString).getOrElse("")) diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/package.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/package.scala deleted file mode 100644 index 2905108..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/package.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.pdsuicommon - -package object logging extends Implicits diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala deleted file mode 100644 index 17c09ed..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/parsers/DimensionsParser.scala +++ /dev/null @@ -1,30 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import scala.util.{Failure, Success, Try} - -class Dimensions(private val xs: Set[String] = Set.empty) { - def contains(x: String): Boolean = xs.isEmpty || xs.contains(x) -} - -object DimensionsParser { - - @deprecated("play-akka transition", "0") - def tryParse(query: Map[String, Seq[String]]): Try[Dimensions] = - tryParse(query.toSeq.flatMap { - case (key, values) => - values.map(value => key -> value) - }) - - def tryParse(query: Seq[(String, String)]): Try[Dimensions] = { - query.collect { case ("dimensions", value) => value } match { - case Nil => Success(new Dimensions()) - - case x +: Nil => - val raw: Set[String] = x.split(",").view.map(_.trim).filter(_.nonEmpty).to[Set] - Success(new Dimensions(raw)) - - case xs => - Failure(new IllegalArgumentException(s"Dimensions are specified ${xs.size} times")) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/PaginationParser.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/PaginationParser.scala deleted file mode 100644 index b59b1a5..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/parsers/PaginationParser.scala +++ /dev/null @@ -1,29 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import xyz.driver.pdsuicommon.db._ -import scala.util._ - -object PaginationParser { - - @deprecated("play-akka transition", "0") - def parse(query: Map[String, Seq[String]]): Try[Pagination] = - parse(query.toSeq.flatMap { - case (key, values) => - values.map(value => key -> value) - }) - - def parse(query: Seq[(String, String)]): Try[Pagination] = { - val IntString = """(\d+)""".r - def validate(field: String, default: Int) = query.collectFirst { case (`field`, size) => size } match { - case Some(IntString(x)) if x.toInt > 0 => x.toInt - case Some(IntString(x)) => throw new ParseQueryArgException((field, s"must greater than zero (found $x)")) - case Some(str) => throw new ParseQueryArgException((field, s"must be an integer (found $str)")) - case None => default - } - - Try { - Pagination(validate("pageSize", Pagination.Default.pageSize), - validate("pageNumber", Pagination.Default.pageNumber)) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/ParseQueryArgException.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/ParseQueryArgException.scala deleted file mode 100644 index 64b3d2e..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/parsers/ParseQueryArgException.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -class ParseQueryArgException(val errors: (String, String)*) extends Exception(errors.mkString(",")) diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala deleted file mode 100644 index aeb6c16..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParser.scala +++ /dev/null @@ -1,178 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import java.util.UUID - -import xyz.driver.pdsuicommon.utils.Implicits.{toCharOps, toStringOps} -import fastparse.all._ -import fastparse.core.Parsed -import xyz.driver.pdsuicommon.db.{SearchFilterBinaryOperation, SearchFilterExpr, SearchFilterNAryOperation} -import xyz.driver.pdsuicommon.utils.Utils._ - -import scala.util.Try - -@SuppressWarnings(Array("org.wartremover.warts.Product", "org.wartremover.warts.Serializable")) -object SearchFilterParser { - - private object BinaryAtomFromTuple { - def unapply(input: (SearchFilterExpr.Dimension, (String, Any))): Option[SearchFilterExpr.Atom.Binary] = { - val (dimensionName, (strOperation, value)) = input - val updatedValue = trimIfString(value) - - parseOperation(strOperation.toLowerCase).map { op => - SearchFilterExpr.Atom.Binary(dimensionName, op, updatedValue.asInstanceOf[AnyRef]) - } - } - } - - private object NAryAtomFromTuple { - // Compiler warning: unchecked since it is eliminated by erasure, if we user Seq[String] - def unapply(input: (SearchFilterExpr.Dimension, (String, Seq[_]))): Option[SearchFilterExpr.Atom.NAry] = { - val (dimensionName, (strOperation, xs)) = input - val updatedValues = xs.map(trimIfString) - - if (strOperation.toLowerCase == "in") { - Some( - SearchFilterExpr.Atom - .NAry(dimensionName, SearchFilterNAryOperation.In, updatedValues.map(_.asInstanceOf[AnyRef]))) - } else { - None - } - } - } - - private def trimIfString(value: Any) = - value match { - case s: String => s.safeTrim - case a => a - } - - private val operationsMapping = { - import xyz.driver.pdsuicommon.db.SearchFilterBinaryOperation._ - - Map[String, SearchFilterBinaryOperation]( - "eq" -> Eq, - "noteq" -> NotEq, - "like" -> Like, - "gt" -> Gt, - "gteq" -> GtEq, - "lt" -> Lt, - "lteq" -> LtEq - ) - } - - private def parseOperation(x: String): Option[SearchFilterBinaryOperation] = operationsMapping.get(x) - - private val whitespaceParser = P(CharPred(_.isSafeWhitespace)) - - val dimensionParser: Parser[SearchFilterExpr.Dimension] = { - val identParser = P( - CharPred(c => c.isLetterOrDigit) - .rep(min = 1)).!.map(s => SearchFilterExpr.Dimension(None, toSnakeCase(s))) - val pathParser = P(identParser.! ~ "." ~ identParser.!) map { - case (left, right) => - SearchFilterExpr.Dimension(Some(toSnakeCase(left)), toSnakeCase(right)) - } - P(pathParser | identParser) - } - - private val commonOperatorParser: Parser[String] = { - P(IgnoreCase("eq") | IgnoreCase("like") | IgnoreCase("noteq")).! - } - - private val numericOperatorParser: Parser[String] = { - P(IgnoreCase("eq") | IgnoreCase("noteq") | ((IgnoreCase("gt") | IgnoreCase("lt")) ~ IgnoreCase("eq").?)).! - } - - private val naryOperatorParser: Parser[String] = P(IgnoreCase("in")).! - - private val isPositiveParser: Parser[Boolean] = P(CharIn("-+").!.?).map { - case Some("-") => false - case _ => true - } - - private val digitsParser: Parser[String] = P(CharIn('0' to '9').rep(min = 1).!) // Exclude Unicode "digits" - - private val numberParser: Parser[String] = P(isPositiveParser ~ digitsParser.! ~ ("." ~ digitsParser).!.?).map { - case (false, intPart, Some(fracPart)) => s"-$intPart.${fracPart.tail}" - case (false, intPart, None) => s"-$intPart" - case (_, intPart, Some(fracPart)) => s"$intPart.${fracPart.tail}" - case (_, intPart, None) => s"$intPart" - } - - private val nAryValueParser: Parser[String] = P(CharPred(_ != ',').rep(min = 1).!) - - private val longParser: Parser[Long] = P(CharIn('0' to '9').rep(min = 1).!.map(_.toLong)) - - private val booleanParser: Parser[Boolean] = - P((IgnoreCase("true") | IgnoreCase("false")).!.map(_.toBoolean)) - - private val hexDigit: Parser[String] = P((CharIn('a' to 'f') | CharIn('A' to 'F') | CharIn('0' to '9')).!) - - private val uuidParser: Parser[UUID] = - P( - hexDigit.rep(8).! ~ "-" ~ hexDigit.rep(4).! ~ "-" ~ hexDigit.rep(4).! ~ "-" ~ hexDigit.rep(4).! ~ "-" ~ hexDigit - .rep(12) - .!).map { - case (group1, group2, group3, group4, group5) => UUID.fromString(s"$group1-$group2-$group3-$group4-$group5") - } - - private val binaryAtomParser: Parser[SearchFilterExpr.Atom.Binary] = P( - dimensionParser ~ whitespaceParser ~ - ((numericOperatorParser.! ~ whitespaceParser ~ (longParser | numberParser.!) ~ End) | - (commonOperatorParser.! ~ whitespaceParser ~ (uuidParser | booleanParser | AnyChar.rep(min = 1).!) ~ End)) - ).map { - case BinaryAtomFromTuple(atom) => atom - } - - private val nAryAtomParser: Parser[SearchFilterExpr.Atom.NAry] = P( - dimensionParser ~ whitespaceParser ~ ( - naryOperatorParser ~ whitespaceParser ~ - ((longParser.rep(min = 1, sep = ",") ~ End) | (booleanParser.rep(min = 1, sep = ",") ~ End) | - (nAryValueParser.!.rep(min = 1, sep = ",") ~ End)) - ) - ).map { - case NAryAtomFromTuple(atom) => atom - } - - private val atomParser: Parser[SearchFilterExpr.Atom] = P(binaryAtomParser | nAryAtomParser) - - @deprecated("play-akka transition", "0") - def parse(query: Map[String, Seq[String]]): Try[SearchFilterExpr] = - parse(query.toSeq.flatMap { - case (key, values) => - values.map(value => key -> value) - }) - - def parse(query: Seq[(String, String)]): Try[SearchFilterExpr] = Try { - query.toList.collect { case ("filters", value) => value } match { - case Nil => SearchFilterExpr.Empty - - case head :: Nil => - atomParser.parse(head) match { - case Parsed.Success(x, _) => x - case e: Parsed.Failure[_, _] => throw new ParseQueryArgException("filters" -> formatFailure(1, e)) - } - - case xs => - val parsed = xs.map(x => atomParser.parse(x)) - val failures: Seq[String] = parsed.zipWithIndex.collect { - case (e: Parsed.Failure[_, _], index) => formatFailure(index, e) - } - - if (failures.isEmpty) { - val filters = parsed.collect { - case Parsed.Success(x, _) => x - } - - SearchFilterExpr.Intersection.create(filters: _*) - } else { - throw new ParseQueryArgException("filters" -> failures.mkString("; ")) - } - } - } - - private def formatFailure(sectionIndex: Int, e: Parsed.Failure[_, _]): String = { - s"section $sectionIndex: ${fastparse.core.ParseError.msg(e.extra.input, e.extra.traced.expected, e.index)}" - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/parsers/SortingParser.scala b/src/main/scala/xyz/driver/pdsuicommon/parsers/SortingParser.scala deleted file mode 100644 index a04d278..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/parsers/SortingParser.scala +++ /dev/null @@ -1,64 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import xyz.driver.pdsuicommon.db.{Sorting, SortingOrder} -import fastparse.all._ -import fastparse.core.Parsed -import xyz.driver.pdsuicommon.utils.Utils._ - -import scala.util.Try - -object SortingParser { - - private val sortingOrderParser: Parser[SortingOrder] = P("-".!.?).map { - case Some(_) => SortingOrder.Descending - case None => SortingOrder.Ascending - } - - private def dimensionSortingParser(validDimensions: Seq[String]): Parser[Sorting.Dimension] = { - P(sortingOrderParser ~ StringIn(validDimensions: _*).!).map { - case (sortingOrder, field) => - val prefixedFields = field.split("\\.", 2) - prefixedFields.size match { - case 1 => Sorting.Dimension(None, toSnakeCase(field), sortingOrder) - case 2 => - Sorting.Dimension(Some(prefixedFields.head).map(toSnakeCase), - toSnakeCase(prefixedFields.last), - sortingOrder) - } - } - } - - private def sequentialSortingParser(validDimensions: Seq[String]): Parser[Sorting.Sequential] = { - P(dimensionSortingParser(validDimensions).rep(min = 1, sep = ",") ~ End).map { dimensions => - Sorting.Sequential(dimensions) - } - } - - @deprecated("play-akka transition", "0") - def parse(validDimensions: Set[String], query: Map[String, Seq[String]]): Try[Sorting] = - parse(validDimensions, query.toSeq.flatMap { - case (key, values) => - values.map(value => key -> value) - }) - - def parse(validDimensions: Set[String], query: Seq[(String, String)]): Try[Sorting] = Try { - query.toList.collect { case ("sort", value) => value } match { - case Nil => Sorting.Sequential(Seq.empty) - - case rawSorting :: Nil => - val parser = sequentialSortingParser(validDimensions.toSeq) - parser.parse(rawSorting) match { - case Parsed.Success(x, _) => x - case e: Parsed.Failure[_, _] => - throw new ParseQueryArgException("sort" -> formatFailure(e)) - } - - case _ => throw new ParseQueryArgException("sort" -> "multiple sections are not allowed") - } - } - - private def formatFailure(e: Parsed.Failure[_, _]): String = { - fastparse.core.ParseError.msg(e.extra.input, e.extra.traced.expected, e.index) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/serialization/Marshaller.scala b/src/main/scala/xyz/driver/pdsuicommon/serialization/Marshaller.scala deleted file mode 100644 index 6702de2..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/serialization/Marshaller.scala +++ /dev/null @@ -1,6 +0,0 @@ -package xyz.driver.pdsuicommon.serialization - -trait Marshaller[T, Repr] { - def read(x: Repr): Option[T] - def write(x: T): Repr -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDataSource.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDataSource.scala deleted file mode 100644 index 63514ec..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDataSource.scala +++ /dev/null @@ -1,23 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.db - -import slick.dbio.DBIO - -import scalaz.OptionT - -trait SlickDataSource[T] { - - val isDictionary: Boolean = false - - /** - * @return New entity - */ - def create(x: T): DBIO[T] - - /** - * @return Updated entity - */ - def update(x: T): OptionT[DBIO, T] - - def delete(x: T): OptionT[DBIO, Unit] - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbAction.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbAction.scala deleted file mode 100644 index 57cc3d4..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbAction.scala +++ /dev/null @@ -1,70 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.db - -import slick.dbio.DBIO -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.synchronization.utils.{FakeIdGen, FakeIdMap} - -import scala.concurrent.ExecutionContext -import scalaz.Monad - -trait SlickDbAction[+T] { - def entity: T -} - -object SlickDbAction { - - final case class Create[T](entity: T) extends SlickDbAction[T] - final case class Update[T](entity: T) extends SlickDbAction[T] - final case class Delete[T](entity: T) extends SlickDbAction[T] - - // Use it only inside of a transaction! - def unsafeRun[T](actions: List[SlickDbAction[T]], dataSource: SlickDataSource[T])( - implicit core: FakeIdGen[T], - executionContext: ExecutionContext, - dbioMonad: Monad[DBIO]): DBIO[FakeIdMap[T]] = { - unsafeRun(DBIO.successful(FakeIdMap.empty))(actions, dataSource) - } - - // Use it only inside of a transaction! - def unsafeRun[T](initial: DBIO[FakeIdMap[T]])(actions: List[SlickDbAction[T]], dataSource: SlickDataSource[T])( - implicit core: FakeIdGen[T], - executionContext: ExecutionContext, - dbioMonad: Monad[DBIO]): DBIO[FakeIdMap[T]] = { - // TODO Squash Updates and Delete to one operation, when bugs in repositories will be fixed - actions.foldLeft(initial) { - case (previousActions, Create(x)) => - for { - r <- previousActions - newArm <- dataSource.create(x) - } yield { - r + (core(newArm) -> newArm) - } - - case (previousActions, Update(x)) => - for { - r <- previousActions - updatedArm <- dataSource.update(x).getOrElse(x) - } yield { - r - core(updatedArm) + (core(updatedArm) -> updatedArm) - } - - case (previousActions, Delete(_)) if dataSource.isDictionary => - previousActions // We don't delete entities from dictionaries - - case (previousActions, Delete(x)) => - for { - r <- previousActions - _ <- dataSource.delete(x).run - } yield { - r - core(x) - } - } - } - - implicit def toPhiString[T](input: SlickDbAction[T])(implicit inner: T => PhiString): PhiString = input match { - case Create(x) => phi"Create($x)" - case Update(x) => phi"Update($x)" - case Delete(x) => phi"Delete($x)" - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbDiff.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbDiff.scala deleted file mode 100644 index c226659..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/db/SlickDbDiff.scala +++ /dev/null @@ -1,52 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.db - -import xyz.driver.pdsuicommon.synchronization.domain.FakeId -import xyz.driver.pdsuicommon.synchronization.utils.{FakeIdGen, Refiner} - -import scala.annotation.tailrec -import scala.collection.breakOut -import scala.collection.immutable.SortedSet - -object SlickDbDiff { - - /** - * Calculates DB-actions to synchronize origEntities with draftEntities. - */ - def calc[DraftT, OrigT](origEntities: Iterable[OrigT], draftEntities: Iterable[DraftT])( - implicit draftFakeIdGen: FakeIdGen[DraftT], - origFakeIdGen: FakeIdGen[OrigT], - refiner: Refiner[DraftT, OrigT]): List[SlickDbAction[OrigT]] = { - val origMap: Map[FakeId, OrigT] = origEntities.map(x => origFakeIdGen(x) -> x)(breakOut) - val uniqueDraftEntities = SortedSet.newBuilder[DraftT](Ordering.by[DraftT, FakeId](draftFakeIdGen)) - uniqueDraftEntities ++= draftEntities - - loop(origMap, uniqueDraftEntities.result(), List.empty) - } - - @tailrec private def loop[DraftT, OrigT](origEntitiesMap: Map[FakeId, OrigT], - draftEntities: Iterable[DraftT], - actions: List[SlickDbAction[OrigT]])( - implicit draftFakeIdGen: FakeIdGen[DraftT], - refiner: Refiner[DraftT, OrigT]): List[SlickDbAction[OrigT]] = { - draftEntities.headOption match { - case None => - // The rest original entities are not a part of draft, so we will delete them - val toDelete: List[SlickDbAction[OrigT]] = origEntitiesMap.values.map(x => SlickDbAction.Delete(x))(breakOut) - actions ++ toDelete - - case Some(currRaw) => - val rawCore = draftFakeIdGen.getFor(currRaw) - val action: Option[SlickDbAction[OrigT]] = origEntitiesMap.get(rawCore) match { - // It is a new entity, because it doesn't exist among originals - case None => Some(SlickDbAction.Create(refiner.refine(currRaw))) - case Some(orig) => - val draft = refiner.refresh(orig, currRaw) - if (draft == orig) None - else Some(SlickDbAction.Update(draft)) - } - - loop(origEntitiesMap - rawCore, draftEntities.tail, action.map(_ :: actions).getOrElse(actions)) - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/domain/FakeId.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/domain/FakeId.scala deleted file mode 100644 index 38e442b..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/domain/FakeId.scala +++ /dev/null @@ -1,14 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.domain - -/* - It is like an Id for entities those haven't an Id, but should be unique. - For example, - RawArm has the name, the kind and the intervention fields. - It has not an Id, but should be identified by the name field. - So, the name field is a fake id for RawArm. - */ -final case class FakeId(value: String) - -object FakeId { - implicit val ordering: Ordering[FakeId] = Ordering.by(_.value) -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/FakeIdGen.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/FakeIdGen.scala deleted file mode 100644 index 196aab1..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/FakeIdGen.scala +++ /dev/null @@ -1,26 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.utils - -import xyz.driver.pdsuicommon.synchronization.domain.FakeId - -/** - * Used to generate a fake id from an entity. - * A fake id is used in comparison between entities with different types, - * for example, RawTrial and Trial. - * - * @see FakeId - */ -trait FakeIdGen[-T] extends (T => FakeId) { - - def getFor(x: T): FakeId - - override def apply(x: T): FakeId = getFor(x) - -} - -object FakeIdGen { - - def create[T](f: T => FakeId) = new FakeIdGen[T] { - override def getFor(x: T): FakeId = f(x) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/Refiner.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/Refiner.scala deleted file mode 100644 index 768b889..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/Refiner.scala +++ /dev/null @@ -1,12 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization.utils - -/** - * Allows to extract a data from the From entity to convert/update in to the To entity. - */ -trait Refiner[-From, To] { - - def refine(raw: From): To - - def refresh(orig: To, update: From): To - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/package.scala b/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/package.scala deleted file mode 100644 index 1b30158..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/synchronization/utils/package.scala +++ /dev/null @@ -1,64 +0,0 @@ -package xyz.driver.pdsuicommon.synchronization - -import java.net.URL -import java.nio.ByteBuffer -import java.util.UUID - -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuicommon.http.HttpFetcher -import xyz.driver.pdsuicommon.json.JsonSerializer -import xyz.driver.pdsuicommon.synchronization.domain.FakeId - -import scala.collection.breakOut -import scala.concurrent.{ExecutionContext, Future} -import scala.io.Codec - -package object utils { - - type FakeIdMap[T] = Map[FakeId, T] - - object FakeIdMap { - - def empty[T]: FakeIdMap[T] = Map.empty - - def create[T](xs: Seq[T])(implicit fakeIdExtractor: FakeIdGen[T]): FakeIdMap[T] = { - xs.map({ x => - fakeIdExtractor.getFor(x) -> x - })(breakOut) - } - - } - - /** - * Requests domain objects from the repository using - * ids of fetched dictionary entities - * - * @param getList repository access function - * @param xs sequence of entity objects - * @param id function that extracts id from the entity - * @tparam Id Type of Id (for example [[LongId]], [[UuidId]]) - * @tparam K Type parameter for Id - * @tparam D Domain object type name - * @tparam E Dictionary entity object type name - */ - def domainFromEntities[K, D, E, Id[_]](getList: Set[Id[K]] => Seq[D], xs: Seq[E])(id: E => Id[K]): Seq[D] = { - getList(xs.map(x => id(x)).toSet) - } - - /** Version of [[domainFromEntities]] for LongId */ - def domainFromEntitiesLong[K, D, E](getList: Set[LongId[K]] => Seq[D], xs: Seq[E])(id: E => Long): Seq[D] = { - domainFromEntities(getList, xs)(e => LongId(id(e))) - } - - /** Version of [[domainFromEntities]] for UuidId */ - def domainFromEntitiesUUID[K, D, E](getList: Set[UuidId[K]] => Seq[D], xs: Seq[E])(id: E => UUID): Seq[D] = { - domainFromEntities(getList, xs)(e => UuidId(id(e))) - } - - def fetch[T](httpFetcher: HttpFetcher, url: URL)(implicit m: Manifest[T], ec: ExecutionContext): Future[T] = { - httpFetcher(url).map { rawContent => - val content = Codec.UTF8.decoder.decode(ByteBuffer.wrap(rawContent)).toString - JsonSerializer.deserialize[T](content) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/CharOps.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/CharOps.scala deleted file mode 100644 index cee9c73..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/CharOps.scala +++ /dev/null @@ -1,31 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -final class CharOps(val self: Char) extends AnyVal { - - import CharOps._ - - def isSafeWhitespace: Boolean = Whitespace.matches(self) - - def isSafeControl: Boolean = JavaIsoControl.matches(self) -} - -// From Guava -private object CharOps { - - object Whitespace { - private val Table: String = - "\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000" + - "\u2029\u000B\u3000\u2008\u2003\u205F\u3000\u1680" + - "\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009" + - "\u3000\u2004\u3000\u3000\u2028\n\u2007\u3000" - - private val Multiplier: Int = 1682554634 - private val Shift: Int = Integer.numberOfLeadingZeros(Table.length - 1) - - def matches(c: Char): Boolean = Table.charAt((Multiplier * c) >>> Shift) == c - } - - object JavaIsoControl { - def matches(c: Char): Boolean = c <= '\u001f' || (c >= '\u007f' && c <= '\u009f') - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/CustomSwaggerJsonFormats.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/CustomSwaggerJsonFormats.scala deleted file mode 100644 index 27560d5..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/CustomSwaggerJsonFormats.scala +++ /dev/null @@ -1,218 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import java.time.{LocalDate, LocalDateTime} - -import io.swagger.models.properties.Property -import spray.json.JsValue -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.formats.json.listresponse._ -import xyz.driver.core.swagger.CustomSwaggerJsonConverter._ -import xyz.driver.entities.patient.CancerType -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue -import xyz.driver.pdsuidomain.entities.export.patient.ExportPatientWithLabels -import xyz.driver.pdsuidomain.entities.export.trial.ExportTrialWithLabels -import xyz.driver.pdsuidomain.fakes.entities.common -import xyz.driver.pdsuidomain.formats.json.bridgeuploadqueue._ -import xyz.driver.pdsuidomain.formats.json.record._ -import xyz.driver.pdsuidomain.formats.json.document._ -import xyz.driver.pdsuidomain.services.CriterionService.RichCriterion -import xyz.driver.pdsuidomain.services.ExtractedDataService.RichExtractedData - -import scala.collection.immutable - -object CustomSwaggerJsonFormats { - - trait MedicalRecordListResponse - trait MedicalRecordIssueListResponse - trait MedicalRecordHistoryListResponse - trait DocumentListResponse - trait DocumentIssueListResponse - trait DocumentHistoryListResponse - trait RichExtractedDataListResponse - trait DocumentTypeListResponse - trait ProviderTypeListResponse - - trait TrialListResponse - trait TrialIssueListResponse - trait TrialHistoryListResponse - trait ArmListResponse - trait InterventionWithArmsListResponse - trait EligibilityArmWithDiseasesListResponse - trait SlotArmListResponse - trait RichCriterionListResponse - trait InterventionTypeListResponse - trait StudyDesignListResponse - trait HypothesisListResponse - - trait PatientListResponse - trait PatientIssueListResponse - trait PatientHistoryListResponse - trait PatientLabelListResponse - trait RichPatientLabelListResponse - trait RichPatientCriterionListResponse - trait RichPatientEligibleTrialListResponse - trait PatientHypothesisListResponse - trait PatientLabelEvidenceViewListResponse - - trait QueueUploadItemListResponse - - val customCommonProperties = immutable.Map[Class[_], Property]( - classOf[LocalDateTime] -> stringProperty(example = Some("2010-12-31'T'18:59:59Z")), - classOf[LocalDate] -> stringProperty(example = Some("2010-12-31")), - classOf[UuidId[_]] -> stringProperty(example = Some("370b0450-35cb-4aab-ba74-0145be75add5")), - classOf[StringId[_]] -> stringProperty(), - classOf[LongId[_]] -> stringProperty(), - classOf[CancerType] -> stringProperty() - ) - - val customCommonObjectsExamples = immutable.Map[Class[_], JsValue]( - classOf[BridgeUploadQueue.Item] -> queueUploadItemFormat.write(common.nextBridgeUploadQueueItem()), - classOf[ProviderType] -> providerTypeFormat.write(common.nextProviderType()), - classOf[DocumentType] -> documentTypeFormat.write(common.nextDocumentType()), - classOf[QueueUploadItemListResponse] -> listResponseWriter[BridgeUploadQueue.Item] - .write(common.nextBridgeUploadQueueItemListResponse()), - classOf[DocumentTypeListResponse] -> listResponseWriter[DocumentType].write(common.nextDocumentTypeListResponse()), - classOf[ProviderTypeListResponse] -> listResponseWriter[ProviderType].write(common.nextProviderTypeListResponse()) - ) - - object trialcuration { - import xyz.driver.pdsuidomain.fakes.entities.trialcuration._ - import xyz.driver.pdsuidomain.fakes.entities.export - import xyz.driver.pdsuidomain.formats.json.export._ - import xyz.driver.pdsuidomain.formats.json.arm._ - import xyz.driver.pdsuidomain.formats.json.slotarm._ - import xyz.driver.pdsuidomain.formats.json.eligibilityarm._ - import xyz.driver.pdsuidomain.formats.json.criterion._ - import xyz.driver.pdsuidomain.formats.json.intervention._ - import xyz.driver.pdsuidomain.formats.json.hypothesis._ - import xyz.driver.pdsuidomain.formats.json.studydesign._ - import xyz.driver.pdsuidomain.formats.json.trial._ - import xyz.driver.pdsuidomain.formats.json.trialhistory._ - import xyz.driver.pdsuidomain.formats.json.trialissue._ - - val customTrialCurationProperties = immutable.Map[Class[_], Property]( - classOf[Trial.Status] -> stringProperty(), - classOf[TrialHistory.Action] -> stringProperty(), - classOf[TrialHistory.State] -> stringProperty() - ) ++ customCommonProperties - - val customTrialCurationObjectsExamples = immutable.Map[Class[_], JsValue]( - classOf[Trial] -> trialFormat.write(nextTrial()), - classOf[Arm] -> armFormat.write(nextArm()), - classOf[TrialHistory] -> trialHistoryFormat.write(nextTrialHistory()), - classOf[TrialIssue] -> trialIssueWriter.write(nextTrialIssue()), - classOf[RichCriterion] -> richCriterionFormat.write(nextRichCriterion()), - classOf[InterventionWithArms] -> interventionFormat.write(nextInterventionWithArms()), - classOf[InterventionType] -> interventionTypeFormat.write(nextInterventionType()), - classOf[Hypothesis] -> hypothesisFormat.write(nextHypothesis()), - classOf[StudyDesign] -> studyDesignFormat.write(nextStudyDesign()), - classOf[ExportTrialWithLabels] -> trialWithLabelsFormat.write(export.nextExportTrialWithLabels()), - classOf[EligibilityArmWithDiseases] -> eligibilityArmWithDiseasesWriter.write(nextEligibilityArmWithDiseases()), - classOf[SlotArm] -> slotArmFormat.write(nextSlotArm()), - classOf[TrialListResponse] -> listResponseWriter[Trial].write(nextTrialListResponse()), - classOf[TrialIssueListResponse] -> listResponseWriter[TrialIssue].write(nextTrialIssueListResponse()), - classOf[TrialHistoryListResponse] -> listResponseWriter[TrialHistory].write(nextTrialHistoryListResponse()), - classOf[ArmListResponse] -> listResponseWriter[Arm].write(nextArmListResponse()), - classOf[InterventionWithArmsListResponse] -> listResponseWriter[InterventionWithArms].write( - nextInterventionWithArmsListResponse()), - classOf[EligibilityArmWithDiseasesListResponse] -> listResponseWriter[EligibilityArmWithDiseases].write( - nextEligibilityArmWithDiseasesListResponse()), - classOf[SlotArmListResponse] -> listResponseWriter[SlotArm].write(nextSlotArmListResponse()), - classOf[RichCriterionListResponse] -> listResponseWriter[RichCriterion].write(nextRichCriterionListResponse()), - classOf[InterventionTypeListResponse] -> listResponseWriter[InterventionType].write( - nextInterventionTypeListResponse()), - classOf[StudyDesignListResponse] -> listResponseWriter[StudyDesign].write(nextStudyDesignListResponse()), - classOf[HypothesisListResponse] -> listResponseWriter[Hypothesis].write(nextHypothesesListResponse()) - ) - } - - object recordprocessing { - import xyz.driver.pdsuidomain.fakes.entities.recordprocessing._ - import xyz.driver.pdsuidomain.fakes.entities.export - import xyz.driver.pdsuidomain.formats.json.export._ - import xyz.driver.pdsuidomain.formats.json.documentissue._ - import xyz.driver.pdsuidomain.formats.json.documenthistory._ - import xyz.driver.pdsuidomain.formats.json.recordissue._ - import xyz.driver.pdsuidomain.formats.json.recordhistory._ - import xyz.driver.pdsuidomain.formats.json.extracteddata._ - - val customRecordProcessingProperties = immutable.Map[Class[_], Property]( - classOf[MedicalRecord.Status] -> stringProperty(), - classOf[MedicalRecordHistory.Action] -> stringProperty(), - classOf[MedicalRecordHistory.State] -> stringProperty(), - classOf[Document.Status] -> stringProperty(), - classOf[Document.RequiredType] -> stringProperty(), - classOf[DocumentHistory.Action] -> stringProperty(), - classOf[DocumentHistory.State] -> stringProperty() - ) ++ customCommonProperties - - val customRecordProcessingObjectsExamples = immutable.Map[Class[_], JsValue]( - classOf[Document] -> documentFormat.write(nextDocument()), - classOf[DocumentIssue] -> documentIssueFormat.write(nextDocumentIssue()), - classOf[DocumentHistory] -> documentHistoryFormat.write(nextDocumentHistory()), - classOf[MedicalRecord] -> recordFormat.write(nextMedicalRecord()), - classOf[MedicalRecordIssue] -> recordIssueFormat.write(nextMedicalRecordIssue()), - classOf[MedicalRecordHistory] -> recordHistoryFormat.write(nextMedicalRecordHistory()), - classOf[RichExtractedData] -> extractedDataFormat.write(nextRichExtractedData()), - classOf[ExportPatientWithLabels] -> patientWithLabelsFormat.write(export.nextExportPatientWithLabels()), - classOf[MedicalRecordListResponse] -> listResponseWriter[MedicalRecord].write(nextMedicalRecordListResponse()), - classOf[MedicalRecordIssueListResponse] -> listResponseWriter[MedicalRecordIssue].write( - nextMedicalRecordIssueListResponse()), - classOf[MedicalRecordHistoryListResponse] -> listResponseWriter[MedicalRecordHistory].write( - nextMedicalRecordHistoryListResponse()), - classOf[DocumentListResponse] -> listResponseWriter[Document].write(nextDocumentListResponse()), - classOf[DocumentIssueListResponse] -> listResponseWriter[DocumentIssue].write(nextDocumentIssueListResponse()), - classOf[DocumentHistoryListResponse] -> listResponseWriter[DocumentHistory].write( - nextDocumentHistoryListResponse()), - classOf[RichExtractedDataListResponse] -> listResponseWriter[RichExtractedData].write( - nextRichExtractedDataListResponse()) - ) ++ customCommonObjectsExamples - } - - object treatmentmatching { - import xyz.driver.pdsuidomain.fakes.entities.treatmentmatching._ - import xyz.driver.pdsuidomain.formats.json.patient._ - import xyz.driver.pdsuidomain.formats.json.patientcriterion._ - import xyz.driver.pdsuidomain.formats.json.patientdefiningcriteria._ - import xyz.driver.pdsuidomain.formats.json.patienteligibletrial._ - import xyz.driver.pdsuidomain.formats.json.patientlabel._ - import xyz.driver.pdsuidomain.formats.json.patienthypothesis._ - import xyz.driver.pdsuidomain.formats.json.patienthistory._ - import xyz.driver.pdsuidomain.formats.json.patientissue._ - - val customTreatmentMatchingProperties = immutable.Map[Class[_], Property]( - classOf[Patient.Status] -> stringProperty(), - classOf[PatientHistory.Action] -> stringProperty(), - classOf[PatientHistory.State] -> stringProperty() - ) ++ customCommonProperties - - val customTreatmentMatchingObjectsExamples = immutable.Map[Class[_], JsValue]( - classOf[Patient] -> patientFormat.write(nextPatient()), - classOf[RichPatientLabel] -> richPatientLabelFormat.write(nextRichPatientLabel()), - classOf[PatientLabel] -> patientLabelDefiningCriteriaWriter.write(nextPatientLabel()), - classOf[RichPatientCriterion] -> richPatientCriterionFormat.write(nextRichPatientCriterion()), - classOf[DraftPatientCriterion] -> draftPatientCriterionFormat.write(nextDraftPatientCriterion()), - classOf[PatientLabelEvidenceView] -> patientLabelEvidenceWriter.write(nextPatientLabelEvidenceView()), - classOf[RichPatientEligibleTrial] -> patientEligibleTrialWriter.write(nextRichPatientEligibleTrial()), - classOf[PatientHypothesis] -> patientHypothesisWriter.write(nextPatientHypothesis()), - classOf[PatientHistory] -> patientHistoryFormat.write(nextPatientHistory()), - classOf[PatientIssue] -> patientIssueWriter.write(nextPatientIssue()), - classOf[PatientListResponse] -> listResponseWriter[Patient].write(nextPatientListResponse()), - classOf[PatientLabelListResponse] -> listResponseWriter[PatientLabel].write(nextPatientLabelListResponse()), - classOf[RichPatientLabelListResponse] -> listResponseWriter[RichPatientLabel].write( - nextRichPatientLabelListResponse()), - classOf[RichPatientCriterionListResponse] -> listResponseWriter[RichPatientCriterion].write( - nextRichPatientCriterionListResponse()), - classOf[PatientLabelEvidenceViewListResponse] -> listResponseWriter[PatientLabelEvidenceView].write( - nextPatientLabelEvidenceViewListResponse()), - classOf[RichPatientEligibleTrialListResponse] -> listResponseWriter[RichPatientEligibleTrial].write( - nextRichPatientEligibleTrialListResponse()), - classOf[PatientHypothesisListResponse] -> listResponseWriter[PatientHypothesis].write( - nextPatientHypothesisListResponse()), - classOf[PatientIssueListResponse] -> listResponseWriter[PatientIssue].write(nextPatientIssuesListResponse()), - classOf[PatientHistoryListResponse] -> listResponseWriter[PatientHistory].write(nextPatientHistoryListResponse()) - ) ++ customCommonObjectsExamples - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala deleted file mode 100644 index e8b1f5c..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala +++ /dev/null @@ -1,18 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import scala.concurrent.{ExecutionContext, Future} -import scala.util.{Failure, Try} - -object FutureUtils { - - def executeSynchronously[T](f: ExecutionContext => Future[T]): Try[T] = { - val future = f { - new ExecutionContext { - override def reportFailure(cause: Throwable): Unit = cause.printStackTrace() - - override def execute(runnable: Runnable): Unit = runnable.run() - } - } - future.value.getOrElse(Failure(new IllegalStateException("Can not evaluate the result of future"))) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala deleted file mode 100644 index 0b18093..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala +++ /dev/null @@ -1,25 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import scala.collection.generic.CanBuildFrom - -object Implicits { - - final class ConditionalAppend[U, T[U] <: TraversableOnce[U]](val c: T[U]) extends AnyVal { - def condAppend(cond: => Boolean, value: U)(implicit cbf: CanBuildFrom[T[U], U, T[U]]): T[U] = { - val col = cbf() - if (cond) { - ((col ++= c) += value).result - } else { - c.asInstanceOf[T[U]] - } - } - } - - implicit def traversableConditionalAppend[U, T[U] <: TraversableOnce[U]](c: T[U]): ConditionalAppend[U, T] = - new ConditionalAppend[U, T](c) - - implicit def toMapOps[K, V](x: Map[K, V]): MapOps[K, V] = new MapOps(x) - - implicit def toCharOps(self: Char): CharOps = new CharOps(self) - implicit def toStringOps(self: String): StringOps = new StringOps(self) -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/MapOps.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/MapOps.scala deleted file mode 100644 index ac9a162..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/MapOps.scala +++ /dev/null @@ -1,10 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -final class MapOps[K, V](val self: Map[K, V]) extends AnyVal { - - def swap: Map[V, Set[K]] = { - self.toList - .groupBy { case (_, v) => v } - .mapValues(_.map { case (k, _) => k }.toSet) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/RandomUtils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/RandomUtils.scala deleted file mode 100644 index faf8703..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/RandomUtils.scala +++ /dev/null @@ -1,19 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import java.util.concurrent.ThreadLocalRandom - -import scala.collection._ - -object RandomUtils { - - private def Random = ThreadLocalRandom.current() - - private val chars: Seq[Char] = ('0' to '9') ++ ('a' to 'z') - - def randomString(len: Int): String = { - (0 until len).map({ _ => - val i = Random.nextInt(0, chars.size) - chars(i) - })(breakOut) - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/ServiceUtils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/ServiceUtils.scala deleted file mode 100644 index 68070f4..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/ServiceUtils.scala +++ /dev/null @@ -1,32 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import xyz.driver.pdsuicommon.db.SearchFilterBinaryOperation.Eq -import xyz.driver.pdsuicommon.db.SearchFilterExpr -import xyz.driver.pdsuicommon.db.SearchFilterExpr.{Atom, Dimension} -import xyz.driver.pdsuicommon.logging._ - -import scala.util.{Failure, Success, Try} - -object ServiceUtils extends PhiLogging { - - def findEqFilter(filter: SearchFilterExpr, fieldName: String): Option[SearchFilterExpr] = { - findEqFilter(filter, Dimension(None, fieldName)) - } - - def findEqFilter(filter: SearchFilterExpr, dimension: Dimension): Option[SearchFilterExpr] = { - filter.find { - case Atom.Binary(`dimension`, Eq, _) => true - case _ => false - } - } - - def convertIdInFilterToLong(value: AnyRef): Option[Long] = { - Try(value.toString.toLong) match { - case Success(id) => - Option(id) - case Failure(e) => - logger.error(phi"Incorrect id format in filter $e") - None - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/StringOps.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/StringOps.scala deleted file mode 100644 index eaac761..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/StringOps.scala +++ /dev/null @@ -1,23 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import xyz.driver.pdsuicommon.utils.Implicits.toCharOps - -final class StringOps(val self: String) extends AnyVal { - - def safeTrim: String = { - def shouldKeep(c: Char): Boolean = !c.isSafeControl && !c.isSafeWhitespace - - if (self.isEmpty) { - "" - } else { - val start = self.indexWhere(shouldKeep) - val end = self.lastIndexWhere(shouldKeep) - - if (start >= 0 && end >= 0) { - self.substring(start, end + 1) - } else { - "" - } - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/Utils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/Utils.scala deleted file mode 100644 index 63b0572..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/Utils.scala +++ /dev/null @@ -1,43 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import java.time.LocalDateTime -import java.util.regex.{Matcher, Pattern} - -object Utils { - - implicit val localDateTimeOrdering: Ordering[LocalDateTime] = Ordering.fromLessThan(_ isBefore _) - - /** - * Hack to avoid scala compiler bug with getSimpleName - * @see https://issues.scala-lang.org/browse/SI-2034 - */ - def getClassSimpleName(klass: Class[_]): String = { - try { - klass.getSimpleName - } catch { - case _: InternalError => - val fullName = klass.getName.stripSuffix("$") - val fullClassName = fullName.substring(fullName.lastIndexOf(".") + 1) - fullClassName.substring(fullClassName.lastIndexOf("$") + 1) - } - } - - def toSnakeCase(str: String): String = - str - .replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2") - .replaceAll("([a-z\\d])([A-Z])", "$1_$2") - .toLowerCase - - def toCamelCase(str: String): String = { - val sb = new StringBuffer() - def loop(m: Matcher): Unit = if (m.find()) { - m.appendReplacement(sb, m.group(1).toUpperCase()) - loop(m) - } - val m: Matcher = Pattern.compile("_(.)").matcher(str) - loop(m) - m.appendTail(sb) - sb.toString - } - -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/validation/ValidationError.scala b/src/main/scala/xyz/driver/pdsuicommon/validation/ValidationError.scala deleted file mode 100644 index 9f466f8..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/validation/ValidationError.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.pdsuicommon.validation - -final case class ValidationError(message: String) diff --git a/src/main/scala/xyz/driver/pdsuicommon/validation/Validators.scala b/src/main/scala/xyz/driver/pdsuicommon/validation/Validators.scala deleted file mode 100644 index a41f87a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/validation/Validators.scala +++ /dev/null @@ -1,39 +0,0 @@ -package xyz.driver.pdsuicommon.validation - -import xyz.driver.pdsuicommon.json.JsonSerializer -import xyz.driver.pdsuicommon.logging._ - -import scala.util.control.NonFatal - -object Validators extends PhiLogging { - - type Validator[Input, Refined] = Input => Either[ValidationError, Refined] - - def generic[T, R](message: String)(f: PartialFunction[T, R]): Validator[T, R] = { value => - if (f.isDefinedAt(value)) Right(f(value)) - else Left(ValidationError(message)) - } - - def nonEmpty[T](field: String): Validator[Option[T], T] = generic(s"$field is empty") { - case Some(x) => x - } - - def nonEmptyString(field: String): Validator[String, String] = generic(s"$field is empty") { - case x if x.nonEmpty => x - } - - def deserializableTo[Refined](field: String)(value: String)( - implicit m: Manifest[Refined]): Either[ValidationError, Refined] = { - try { - Right(JsonSerializer.deserialize[Refined](value)) - } catch { - case NonFatal(e) => - logger.error(phi"Can not deserialize the ${Unsafe(field)}: $e") - Left(ValidationError(s"$field is invalid")) - } - } - - def success[T](result: T): Either[Nothing, T] = Right(result) - - def fail(message: String): Either[ValidationError, Nothing] = Left(ValidationError(message)) -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/ListResponse.scala b/src/main/scala/xyz/driver/pdsuidomain/ListResponse.scala deleted file mode 100644 index c6dce7b..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/ListResponse.scala +++ /dev/null @@ -1,24 +0,0 @@ -package xyz.driver.pdsuidomain - -import java.time.LocalDateTime - -import xyz.driver.pdsuicommon.db.Pagination - -final case class ListResponse[+T](items: Seq[T], meta: ListResponse.Meta) - -object ListResponse { - - final case class Meta(itemsCount: Int, pageNumber: Int, pageSize: Int, lastUpdate: Option[LocalDateTime]) - - object Meta { - def apply(itemsCount: Int, pagination: Pagination, lastUpdate: Option[LocalDateTime]): Meta = { - Meta( - itemsCount, - pagination.pageNumber, - pagination.pageSize, - lastUpdate - ) - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Arm.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Arm.scala deleted file mode 100644 index 2190b8d..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/Arm.scala +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDateTime - -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuicommon.logging._ - -final case class Arm(id: LongId[Arm], - name: String, - originalName: String, - trialId: StringId[Trial], - deleted: Option[LocalDateTime] = None) - -object Arm { - - implicit def toPhiString(x: Arm): PhiString = { - import x._ - phi"Arm(id=$id, name=${Unsafe(x.name)}, trialId=${Unsafe(x.trialId)})" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala deleted file mode 100644 index 26ced22..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala +++ /dev/null @@ -1,57 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import xyz.driver.entities.labels.{Label, LabelCategory} -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.Criterion.Meta.Evidence - -final case class Criterion(id: LongId[Criterion], - trialId: StringId[Trial], - text: Option[String], - isCompound: Boolean, - meta: String, - inclusion: Option[Boolean]) { - - def isValid: Boolean = text.nonEmpty && Option(meta).isDefined -} - -object Criterion { - - final case class Meta(evidence: Evidence) - - object Meta { - final case class Evidence(pageRatio: Double, start: TextLayerPosition, end: TextLayerPosition) - final case class TextLayerPosition(page: Integer, index: Integer, offset: Integer) - } - - implicit def toPhiString(x: Criterion): PhiString = { - import x._ - phi"Criterion(id=$id, trialId=$trialId, isCompound=$isCompound)" - } -} - -final case class CriterionArm(criterionId: LongId[Criterion], armId: LongId[EligibilityArm]) - -object CriterionArm { - - implicit def toPhiString(x: CriterionArm): PhiString = { - import x._ - phi"CriterionArm(criterionId=$criterionId, armId=$armId)" - } -} - -final case class CriterionLabel(id: LongId[CriterionLabel], - labelId: Option[LongId[Label]], - criterionId: LongId[Criterion], - categoryId: Option[LongId[LabelCategory]], - value: Option[Boolean], - isDefining: Boolean) - -object CriterionLabel { - - implicit def toPhiString(x: CriterionLabel): PhiString = { - import x._ - phi"CriterionLabel(id=$id, labelId=$labelId, criterionId=$criterionId, " + - phi"categoryId=$categoryId, value=$value, isDefining=$isDefining)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/DirectReport.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/DirectReport.scala deleted file mode 100644 index f35c3fd..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/DirectReport.scala +++ /dev/null @@ -1,24 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDate - -import xyz.driver.entities.assays.AssayType -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.domain.UuidId - -object DirectReport { - implicit def toPhiString(x: DirectReport): PhiString = { - import x._ - phi"DirectReport(id=$id, patientId=$patientId, reportType=${Unsafe(reportType)}, date=${Unsafe(date)}, " + - phi"documentType=${Unsafe(documentType)}, providerType=${Unsafe(providerType)}, " + - phi"providerName=${Unsafe(providerName)})" - } -} - -final case class DirectReport(id: UuidId[DirectReport], - patientId: UuidId[Patient], - reportType: AssayType, - date: LocalDate, - documentType: DocumentType, - providerType: ProviderType, - providerName: String) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Document.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Document.scala deleted file mode 100644 index 0669baf..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/Document.scala +++ /dev/null @@ -1,492 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.{LocalDate, LocalDateTime, ZoneId} - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties -import com.fasterxml.jackson.core.{JsonGenerator, JsonParser} -import com.fasterxml.jackson.databind._ -import com.fasterxml.jackson.databind.annotation.{JsonDeserialize, JsonSerialize} -import xyz.driver.core.auth.User -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.utils.Utils -import xyz.driver.pdsuicommon.validation.Validators -import xyz.driver.pdsuicommon.validation.Validators.Validator -import xyz.driver.pdsuidomain.entities.Document.Meta - -import scalaz.Equal -import scalaz.syntax.equal._ -import scalaz.Scalaz.stringInstance - -sealed trait ProviderType { - val id: LongId[ProviderType] - val name: String -} - -object ProviderType { - - case object MedicalOncology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](1) - val name: String = "Medical Oncology" - } - - case object Surgery extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](2) - val name: String = "Surgery" - } - - case object Pathology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](3) - val name: String = "Pathology" - } - - case object MolecularPathology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](4) - val name: String = "Molecular Pathology" - } - - case object LaboratoryMedicine extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](5) - val name: String = "Laboratory Medicine" - } - - case object Radiology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](6) - val name: String = "Radiology" - } - - case object InterventionalRadiology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](7) - val name: String = "Interventional Radiology" - } - - case object RadiationOncology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](8) - val name: String = "Radiation Oncology" - } - - case object PrimaryCare extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](9) - val name: String = "Primary Care" - } - - case object Cardiology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](10) - val name: String = "Cardiology" - } - - case object Dermatology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](11) - val name: String = "Dermatology" - } - - case object Ophthalmology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](12) - val name: String = "Ophthalmology" - } - - case object Gastroenterology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](13) - val name: String = "Gastroenterology" - } - - case object Neurology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](14) - val name: String = "Neurology" - } - - case object Psychiatry extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](15) - val name: String = "Psychiatry" - } - - case object Gynecology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](16) - val name: String = "Gynecology" - } - - case object InfectiousDisease extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](17) - val name: String = "Infectious Disease" - } - - case object Immunology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](18) - val name: String = "Immunology" - } - - case object Nephrology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](19) - val name: String = "Nephrology" - } - - case object Rheumatology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](20) - val name: String = "Rheumatology" - } - - case object Cytology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](21) - val name: String = "Cytology" - } - - case object Otolaryngology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](22) - val name: String = "Otolaryngology" - } - - case object Anesthesiology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](23) - val name: String = "Anesthesiology" - } - - case object Urology extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](24) - val name: String = "Urology" - } - - case object PalliativeCare extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](25) - val name: String = "Palliative Care" - } - - case object EmergencyMedicine extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](26) - val name: String = "Emergency Medicine" - } - - case object SocialWork extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](27) - val name: String = "Social Work" - } - - case object NA extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](28) - val name: String = "N/A" - } - - case object Other extends ProviderType { - val id: LongId[ProviderType] = LongId[ProviderType](29) - val name: String = "Other" - } - - val All = Seq[ProviderType]( - MedicalOncology, - Surgery, - Pathology, - MolecularPathology, - LaboratoryMedicine, - Radiology, - InterventionalRadiology, - RadiationOncology, - PrimaryCare, - Cardiology, - Dermatology, - Ophthalmology, - Gastroenterology, - Neurology, - Psychiatry, - Gynecology, - InfectiousDisease, - Immunology, - Nephrology, - Rheumatology, - Cytology, - Otolaryngology, - Anesthesiology, - Urology, - PalliativeCare, - EmergencyMedicine, - SocialWork, - NA, - Other - ) - - def fromString(txt: String): Option[ProviderType] = { - All.find(_.name === txt) - } - - implicit def toPhiString(x: ProviderType): PhiString = { - import x._ - phi"ProviderType(id=$id, category=${Unsafe(name)})" - } -} - -sealed trait DocumentType { - val id: LongId[DocumentType] - val name: String -} - -object DocumentType { - - case object OutpatientPhysicianNote extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](1) - val name: String = "Outpatient Physician Note" - } - - case object DischargeNote extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](2) - val name: String = "Discharge Note" - } - - case object LaboratoryReport extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](3) - val name: String = "Laboratory Report" - } - - case object MedicationList extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](4) - val name: String = "Medication List" - } - - case object HospitalizationNote extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](5) - val name: String = "Hospitalization Note" - } - - case object PathologyReport extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](6) - val name: String = "Pathology Report" - } - - case object RadiologyReport extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](7) - val name: String = "Radiology Report" - } - - case object OperativeProcedureReport extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](8) - val name: String = "Operative/Procedure Report" - } - - case object MedicationAdministration extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](9) - val name: String = "Medication Administration" - } - - case object SocialWorkCaseManagementNote extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](10) - val name: String = "Social Work/Case Management Note" - } - - case object NonPhysicianProviderNote extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](11) - val name: String = "Non-physician Provider Note" - } - - case object Administrative extends DocumentType { - val id: LongId[DocumentType] = LongId[DocumentType](12) - val name: String = "Administrative" - } - - val All = Seq[DocumentType]( - OutpatientPhysicianNote, - DischargeNote, - LaboratoryReport, - MedicationList, - HospitalizationNote, - PathologyReport, - RadiologyReport, - OperativeProcedureReport, - MedicationAdministration, - SocialWorkCaseManagementNote, - NonPhysicianProviderNote, - Administrative - ) - - def fromString(txt: String): Option[DocumentType] = { - All.find(_.name === txt) - } - - implicit def equal: Equal[DocumentType] = Equal.equal[DocumentType](_ == _) - - implicit def toPhiString(x: DocumentType): PhiString = { - import x._ - phi"DocumentType(id=$id, name=${Unsafe(name)})" - } -} - -object Document { - - final case class Meta(startPage: Double, endPage: Double) - - class DocumentStatusSerializer extends JsonSerializer[Status] { - def serialize(value: Status, gen: JsonGenerator, serializers: SerializerProvider): Unit = { - gen.writeString(value.toString.toUpperCase) - } - } - - class DocumentStatusDeserializer extends JsonDeserializer[Status] { - def deserialize(parser: JsonParser, context: DeserializationContext): Status = { - val value = parser.getValueAsString - Option(value).fold[Document.Status](Status.New /* Default document status */ ) { v => - Status.All.find(_.toString.toUpperCase == v) match { - case None => throw new RuntimeJsonMappingException(s"$v is not valid Document.Status") - case Some(status) => status - } - } - } - } - - // Product with Serializable fixes issue: - // Set(New, Organized) has type Set[Status with Product with Serializable] - @JsonDeserialize(using = classOf[DocumentStatusDeserializer]) - @JsonSerialize(using = classOf[DocumentStatusSerializer]) - sealed trait Status extends Product with Serializable { - - def oneOf(xs: Status*): Boolean = xs.contains(this) - - def oneOf(xs: Set[Status]): Boolean = xs.contains(this) - - } - - object Status { - case object New extends Status - case object Organized extends Status - case object Extracted extends Status - case object Done extends Status - case object Flagged extends Status - case object Archived extends Status - - val All = Set[Status](New, Organized, Extracted, Done, Flagged, Archived) - val AllPrevious = Set[Status](Organized, Extracted) - - def fromString(status: String): Option[Status] = status match { - case "New" => Some(Status.New) - case "Organized" => Some(Status.Organized) - case "Extracted" => Some(Status.Extracted) - case "Done" => Some(Status.Done) - case "Flagged" => Some(Status.Flagged) - case "Archived" => Some(Status.Archived) - case _ => None - } - - def statusToString(x: Status): String = x match { - case Status.New => "New" - case Status.Organized => "Organized" - case Status.Extracted => "Extracted" - case Status.Done => "Done" - case Status.Flagged => "Flagged" - case Status.Archived => "Archived" - } - - implicit def toPhiString(x: Status): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) - } - - sealed trait RequiredType extends Product with Serializable { - - def oneOf(xs: RequiredType*): Boolean = xs.contains(this) - - def oneOf(xs: Set[RequiredType]): Boolean = xs.contains(this) - - } - - object RequiredType { - case object OPN extends RequiredType - case object PN extends RequiredType - - val All = Set[RequiredType](OPN, PN) - - def fromString(tpe: String): Option[RequiredType] = tpe match { - case "OPN" => Some(RequiredType.OPN) - case "PN" => Some(RequiredType.PN) - case _ => None - } - - def requiredTypeToString(x: RequiredType): String = x match { - case RequiredType.OPN => "OPN" - case RequiredType.PN => "PN" - } - - implicit def toPhiString(x: RequiredType): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) - } - - implicit def toPhiString(x: Document): PhiString = { - import x._ - phi"Document(id=$id, status=$status, assignee=${Unsafe(assignee)}, " + - phi"previousAssignee=${Unsafe(previousAssignee)}, " + - phi"lastActiveUserId=${Unsafe(lastActiveUserId)}, recordId=$recordId)" - } - - val validator: Validator[Document, Document] = { input => - for { - typeId <- Validators.nonEmpty("typeId")(input.typeId).right - - providerTypeId <- Validators.nonEmpty("providerTypeId")(input.providerTypeId).right - - institutionName <- Validators.nonEmpty("institutionName")(input.institutionName).right - - meta <- Validators.nonEmpty("meta")(input.meta).right - - startDate <- Validators.nonEmpty("startDate")(input.startDate).right - - isOrderRight <- (input.endDate match { - case Some(endDate) if startDate.isAfter(endDate) => - Validators.fail("The start date should be less, than the end one") - - case _ => Validators.success(true) - }).right - - areDatesInThePast <- { - val dates = List(input.startDate, input.endDate).flatten - val now = LocalDate.now() - val hasInvalid = dates.exists(_.isAfter(now)) - - if (hasInvalid) Validators.fail("Dates should be in the past") - else Validators.success(true) - }.right - } yield input - } - -} - -@JsonIgnoreProperties(value = Array("valid")) -final case class Document(id: LongId[Document] = LongId(0L), - status: Document.Status, - previousStatus: Option[Document.Status], - assignee: Option[xyz.driver.core.Id[User]], - previousAssignee: Option[xyz.driver.core.Id[User]], - lastActiveUserId: Option[xyz.driver.core.Id[User]], - recordId: LongId[MedicalRecord], - physician: Option[String], - typeId: Option[LongId[DocumentType]], // not null - providerName: Option[String], // not null - providerTypeId: Option[LongId[ProviderType]], // not null - requiredType: Option[Document.RequiredType], - institutionName: Option[String], - meta: Option[TextJson[Meta]], // not null - startDate: Option[LocalDate], // not null - endDate: Option[LocalDate], - lastUpdate: LocalDateTime, - labelVersion: Int) { - - import Document.Status._ - - if (previousStatus.nonEmpty) { - assert(AllPrevious.contains(previousStatus.get), s"Previous status has invalid value: ${previousStatus.get}") - } - - def getRequiredType(documentTypeName: String, providerTypeName: String): Option[Document.RequiredType] = { - import DocumentType.{OutpatientPhysicianNote, PathologyReport} - import ProviderType.MedicalOncology - - (DocumentType.fromString(documentTypeName), ProviderType.fromString(providerTypeName), startDate) match { - case (Some(OutpatientPhysicianNote), Some(MedicalOncology), Some(date)) - if !(date.isAfter(LocalDate.now(ZoneId.of("Z"))) || date.isBefore( - LocalDate.now(ZoneId.of("Z")).minusMonths(6))) => - Some(Document.RequiredType.OPN) - - case (Some(PathologyReport), _, _) => Some(Document.RequiredType.PN) - - case _ => None - } - } - - // TODO: with the current business logic code this constraint sometimes harmful - // require(status match { - // case Document.Status.New if assignee.isDefined => false - // case Document.Status.Done if assignee.isDefined => false - // case _ => true - // }, "Assignee can't be defined in New or Done statuses") - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/DocumentHistory.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/DocumentHistory.scala deleted file mode 100644 index f076074..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/DocumentHistory.scala +++ /dev/null @@ -1,98 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.{LocalDateTime, ZoneId} - -import xyz.driver.core.auth.User -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.utils.Utils -import xyz.driver.pdsuidomain.entities.DocumentHistory.{Action, _} - -object DocumentHistory { - - implicit def toPhiString(x: DocumentHistory): PhiString = { - import x._ - phi"DocumentHistory(id=$id, executor=${Unsafe(executor)}, documentId=$documentId, state=$state, action=$action, " + - phi"created=$created)" - } - - sealed trait State - object State { - case object New extends State - case object Extract extends State - case object Review extends State - case object Done extends State - case object Flag extends State - case object Archive extends State - - val All: Set[State] = Set( - State.New, - State.Extract, - State.Review, - State.Done, - State.Flag, - State.Archive - ) - - private val stateToName: Map[State, String] = - All.map(s => s -> s.toString).toMap - - val fromString: PartialFunction[String, State] = - for ((k, v) <- stateToName) yield (v, k) - - def stateToString: State => String = stateToName - - implicit def toPhiString(x: State): PhiString = - Unsafe(Utils.getClassSimpleName(x.getClass)) - } - - sealed trait Action extends Product with Serializable { - - def oneOf(xs: Action*): Boolean = xs.contains(this) - - def oneOf(xs: Set[Action]): Boolean = xs.contains(this) - - } - - object Action { - case object Start extends Action - case object Submit extends Action - case object Unassign extends Action - case object Resolve extends Action - case object Flag extends Action - case object Archive extends Action - case object PostEvidence extends Action - case object CreateDocument extends Action - case object ReadDocument extends Action - - val All: Set[Action] = Set( - Action.Start, - Action.Submit, - Action.Unassign, - Action.Resolve, - Action.Flag, - Action.Archive, - Action.PostEvidence, - Action.CreateDocument, - Action.ReadDocument - ) - - private val actionToName: Map[Action, String] = - All.map(a => a -> a.toString).toMap - - val fromString: PartialFunction[String, Action] = - for ((k, v) <- actionToName) yield (v, k) - - def actionToString: Action => String = actionToName - - implicit def toPhiString(x: Action): PhiString = - Unsafe(Utils.getClassSimpleName(x.getClass)) - } -} - -final case class DocumentHistory(id: LongId[DocumentHistory], - executor: xyz.driver.core.Id[User], - documentId: LongId[Document], - state: State, - action: Action, - created: LocalDateTime = LocalDateTime.now(ZoneId.of("Z"))) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/DocumentIssue.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/DocumentIssue.scala deleted file mode 100644 index 279ef38..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/DocumentIssue.scala +++ /dev/null @@ -1,24 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDateTime - -import xyz.driver.core.auth.User -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.logging._ - -final case class DocumentIssue(id: LongId[DocumentIssue], - userId: xyz.driver.core.Id[User], - documentId: LongId[Document], - startPage: Option[Double], - endPage: Option[Double], - lastUpdate: LocalDateTime, - isDraft: Boolean, - text: String, - archiveRequired: Boolean) - -object DocumentIssue { - implicit def toPhiString(x: DocumentIssue): PhiString = { - import x._ - phi"DocumentIssue(id=$id, userId=${Unsafe(userId)}, documentId=$documentId)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/EligibilityArm.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/EligibilityArm.scala deleted file mode 100644 index 50b49ad..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/EligibilityArm.scala +++ /dev/null @@ -1,42 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDateTime - -import xyz.driver.entities.patient.CancerType -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuicommon.logging._ - -final case class EligibilityArm(id: LongId[EligibilityArm], - name: String, - originalName: String, - trialId: StringId[Trial], - deleted: Option[LocalDateTime] = None) - -object EligibilityArm { - - implicit def toPhiString(x: EligibilityArm): PhiString = { - import x._ - phi"Arm(id=$id, name=${Unsafe(x.name)}, trialId=${Unsafe(x.trialId)})" - } -} - -final case class EligibilityArmDisease(eligibilityArmId: LongId[EligibilityArm], disease: CancerType) - -object EligibilityArmDisease { - - implicit def toPhiString(x: EligibilityArmDisease): PhiString = { - phi"EligibilityArmDisease(eligibilityArmId=${Unsafe(x.eligibilityArmId)}, disease=${Unsafe(x.disease)})" - } - -} - -final case class EligibilityArmWithDiseases(eligibilityArm: EligibilityArm, - eligibilityArmDiseases: Seq[EligibilityArmDisease]) - -object EligibilityArmWithDiseases { - - implicit def toPhiString(x: EligibilityArmWithDiseases): PhiString = { - import x._ - phi"EligibilityArmWithDiseases(eligibilityArm=$eligibilityArm, eligibilityArmDiseases=$eligibilityArmDiseases)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala deleted file mode 100644 index 569375a..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala +++ /dev/null @@ -1,48 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import xyz.driver.entities.labels.{Label, LabelCategory, LabelValue} -import xyz.driver.pdsuicommon.domain.{LongId, TextJson} -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.ExtractedData.Meta - -final case class ExtractedData(id: LongId[ExtractedData] = LongId(0L), - documentId: LongId[Document], - keywordId: Option[LongId[Keyword]], - evidenceText: Option[String], - meta: Option[TextJson[Meta]]) { - - def isValid: Boolean = evidenceText.getOrElse("") != "" && meta.nonEmpty - -} - -object ExtractedData { - - final case class Meta(keyword: Option[Meta.Keyword], evidence: Option[Meta.Evidence]) - - object Meta { - final case class Evidence(pageRatio: Double, start: TextLayerPosition, end: TextLayerPosition) - - final case class TextLayerPosition(page: Integer, index: Integer, offset: Integer) - - final case class Keyword(page: Integer, pageRatio: Option[Double], index: Integer, sortIndex: String) - } - - implicit def toPhiString(x: ExtractedData): PhiString = { - import x._ - phi"ExtractedData(id=$id, documentId=$documentId, keywordId=$keywordId)" - } -} - -object ExtractedDataLabel { - - implicit def toPhiString(x: ExtractedDataLabel): PhiString = { - import x._ - phi"ExtractedDataLabel(id=$id, dataId=$dataId, labelId=$labelId, categoryId=$categoryId, value=${Unsafe(value)})" - } -} - -final case class ExtractedDataLabel(id: LongId[ExtractedDataLabel], - dataId: LongId[ExtractedData], - labelId: Option[LongId[Label]], - categoryId: Option[LongId[LabelCategory]], - value: Option[LabelValue]) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Hypothesis.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Hypothesis.scala deleted file mode 100644 index 47b87ff..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/Hypothesis.scala +++ /dev/null @@ -1,13 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuicommon.logging._ - -final case class Hypothesis(id: UuidId[Hypothesis], name: String, treatmentType: String, description: String) - -object Hypothesis { - implicit def toPhiString(x: Hypothesis): PhiString = { - import x._ - phi"Hypothesis(id=$id, name=${Unsafe(name)})" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala deleted file mode 100644 index be51e4f..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala +++ /dev/null @@ -1,215 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.InterventionType.DeliveryMethod -import xyz.driver.pdsuidomain.entities.InterventionType.DeliveryMethod._ - -import scalaz.syntax.equal._ -import scalaz.Scalaz.stringInstance - -sealed trait InterventionType { - val id: LongId[InterventionType] - val name: String - val deliveryMethods: Set[DeliveryMethod] -} - -object InterventionType { - - final case object Chemotherapy extends InterventionType { - val id: LongId[InterventionType] = LongId[InterventionType](2) - val name: String = "Chemotherapy" - val deliveryMethods: Set[DeliveryMethod] = commonMethods - } - - final case object TargetedTherapy extends InterventionType { - val id: LongId[InterventionType] = LongId[InterventionType](3) - val name: String = "Targeted therapy" - val deliveryMethods: Set[DeliveryMethod] = commonMethods - } - - final case object Immunotherapy extends InterventionType { - val id: LongId[InterventionType] = LongId[InterventionType](4) - val name: String = "Immunotherapy" - val deliveryMethods: Set[DeliveryMethod] = commonMethods - } - - final case object HormoneTherapy extends InterventionType { - val id: LongId[InterventionType] = LongId[InterventionType](6) - val name: String = "Hormone therapy" - val deliveryMethods: Set[DeliveryMethod] = commonMethods - } - - final case object Other extends InterventionType { - val id: LongId[InterventionType] = LongId[InterventionType](7) - val name: String = "Other" - val deliveryMethods: Set[DeliveryMethod] = commonMethods - } - - final case object Radiation extends InterventionType { - val id: LongId[InterventionType] = LongId[InterventionType](8) - val name: String = "Radiation" - val deliveryMethods: Set[DeliveryMethod] = Set( - ExternalRadiationTherapy, - Brachytherapy, - SystemicRadiationTherapyIV, - SystemicRadiationTherapyOral, - ProtonBeamTherapy - ) - } - - final case object SurgeryProcedure extends InterventionType { - val id: LongId[InterventionType] = LongId[InterventionType](9) - val name: String = "Surgery/Procedure" - val deliveryMethods: Set[DeliveryMethod] = Set( - RadioFrequencyAblationRFA, - Cryoablation, - TherapeuticConventionalSurgery, - RoboticAssistedLaparoscopicSurgery - ) - } - - def typeFromString(txt: String): Option[InterventionType] = { - All.values.find(_.name === txt) - } - - sealed trait DeliveryMethod - object DeliveryMethod { - case object IntravenousInfusionIV extends DeliveryMethod - case object IntramuscularInjection extends DeliveryMethod - case object SubcutaneousInjection extends DeliveryMethod - case object IntradermalInjection extends DeliveryMethod - case object SpinalInjection extends DeliveryMethod - case object Oral extends DeliveryMethod - case object Topical extends DeliveryMethod - case object TransdermalPatch extends DeliveryMethod - case object Inhalation extends DeliveryMethod - case object Rectal extends DeliveryMethod - case object ExternalRadiationTherapy extends DeliveryMethod - case object Brachytherapy extends DeliveryMethod - case object SystemicRadiationTherapyIV extends DeliveryMethod - case object SystemicRadiationTherapyOral extends DeliveryMethod - case object ProtonBeamTherapy extends DeliveryMethod - case object RadioFrequencyAblationRFA extends DeliveryMethod - case object Cryoablation extends DeliveryMethod - case object TherapeuticConventionalSurgery extends DeliveryMethod - case object RoboticAssistedLaparoscopicSurgery extends DeliveryMethod - - def fromString: PartialFunction[String, DeliveryMethod] = { - case "Intravenous Infusion (IV)" => IntravenousInfusionIV - case "Intramuscular Injection" => IntramuscularInjection - case "Subcutaneous Injection" => SubcutaneousInjection - case "Intradermal Injection" => IntradermalInjection - case "Spinal Injection" => SpinalInjection - case "Oral" => Oral - case "Topical" => Topical - case "Transdermal Patch" => TransdermalPatch - case "Inhalation" => Inhalation - case "Rectal" => Rectal - case "External Radiation Therapy" => ExternalRadiationTherapy - case "Brachytherapy" => Brachytherapy - case "Systemic Radiation Therapy (IV)" => SystemicRadiationTherapyIV - case "Systemic Radiation Therapy (Oral)" => SystemicRadiationTherapyOral - case "Proton Beam Therapy" => ProtonBeamTherapy - case "Radio-Frequency Ablation (RFA)" => RadioFrequencyAblationRFA - case "Cryoablation" => Cryoablation - case "Therapeutic Conventional Surgery" => TherapeuticConventionalSurgery - case "Robotic Assisted Laparoscopic Surgery" => RoboticAssistedLaparoscopicSurgery - } - - def methodToString(x: DeliveryMethod): String = x match { - case IntravenousInfusionIV => "Intravenous Infusion (IV)" - case IntramuscularInjection => "Intramuscular Injection" - case SubcutaneousInjection => "Subcutaneous Injection" - case IntradermalInjection => "Intradermal Injection" - case SpinalInjection => "Spinal Injection" - case Oral => "Oral" - case Topical => "Topical" - case TransdermalPatch => "Transdermal Patch" - case Inhalation => "Inhalation" - case Rectal => "Rectal" - case ExternalRadiationTherapy => "External Radiation Therapy" - case Brachytherapy => "Brachytherapy" - case SystemicRadiationTherapyIV => "Systemic Radiation Therapy (IV)" - case SystemicRadiationTherapyOral => "Systemic Radiation Therapy (Oral)" - case ProtonBeamTherapy => "Proton Beam Therapy" - case RadioFrequencyAblationRFA => "Radio-Frequency Ablation (RFA)" - case Cryoablation => "Cryoablation" - case TherapeuticConventionalSurgery => "Therapeutic Conventional Surgery" - case RoboticAssistedLaparoscopicSurgery => "Robotic Assisted Laparoscopic Surgery" - } - } - - val commonMethods: Set[DeliveryMethod] = Set[DeliveryMethod]( - IntravenousInfusionIV, - IntramuscularInjection, - SubcutaneousInjection, - IntradermalInjection, - SpinalInjection, - Oral, - Topical, - TransdermalPatch, - Inhalation, - Rectal - ) - - val All: Map[LongId[InterventionType], InterventionType] = Map[LongId[InterventionType], InterventionType]( - LongId[InterventionType](2) -> Chemotherapy, - LongId[InterventionType](3) -> TargetedTherapy, - LongId[InterventionType](4) -> Immunotherapy, - LongId[InterventionType](6) -> HormoneTherapy, - LongId[InterventionType](7) -> Other, - LongId[InterventionType](8) -> Radiation, - LongId[InterventionType](9) -> SurgeryProcedure - ) - - implicit def toPhiString(x: InterventionType): PhiString = { - import x._ - phi"InterventionType(id=$id, name=${Unsafe(name)})" - } -} - -final case class InterventionArm(armId: LongId[SlotArm], interventionId: LongId[Intervention]) - -object InterventionArm { - implicit def toPhiString(x: InterventionArm): PhiString = { - import x._ - phi"InterventionArm(armId=$armId, interventionId=$interventionId)" - } -} - -final case class Intervention(id: LongId[Intervention], - trialId: StringId[Trial], - name: String, - originalName: String, - typeId: Option[LongId[InterventionType]], - originalType: Option[String], - dosage: String, - originalDosage: String, - isActive: Boolean, - deliveryMethod: Option[String]) { - def deliveryMethodIsCorrect: Boolean = { - if (this.typeId.nonEmpty && this.deliveryMethod.nonEmpty) { - InterventionType.All - .getOrElse(this.typeId.get, throw new IllegalArgumentException(s"Not found Intervention type ${this.typeId}")) - .deliveryMethods - .contains(DeliveryMethod.fromString(this.deliveryMethod.get)) - } else true - } -} - -object Intervention { - implicit def toPhiString(x: Intervention): PhiString = { - import x._ - phi"Intervention(id=$id, trialId=$trialId, name=${Unsafe(name)}, typeId=$typeId, isActive=$isActive, deliveryMethod=${Unsafe(deliveryMethod)})" - } -} - -final case class InterventionWithArms(intervention: Intervention, arms: List[InterventionArm]) - -object InterventionWithArms { - implicit def toPhiString(x: InterventionWithArms): PhiString = { - import x._ - phi"InterventionWithArms(intervention=$intervention, arms=$arms)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Keyword.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Keyword.scala deleted file mode 100644 index a984f92..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/Keyword.scala +++ /dev/null @@ -1,32 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import xyz.driver.entities.labels.Label -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.logging._ - -final case class Keyword(id: LongId[Keyword], keyword: String) - -object Keyword { - implicit def toPhiString(x: Keyword): PhiString = { - import x._ - phi"Keyword(id=$id, keyword=${Unsafe(keyword)})" - } -} - -final case class KeywordWithLabels(keyword: Keyword, labels: List[Label]) - -object KeywordWithLabels { - implicit def toPhiString(x: KeywordWithLabels): PhiString = { - import x._ - phi"KeywordWithLabels(keyword=$keyword, ${Unsafe(labels)}" - } -} - -final case class KeywordLabel(keywordId: LongId[Keyword], labelId: LongId[Label]) - -object KeywordLabel { - implicit def toPhiString(x: KeywordLabel): PhiString = { - import x._ - phi"KeywordLabel($keywordId, $labelId)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecord.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecord.scala deleted file mode 100644 index cf13d1a..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecord.scala +++ /dev/null @@ -1,164 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.nio.channels.ReadableByteChannel -import java.time.LocalDateTime - -import com.fasterxml.jackson.annotation.JsonSubTypes.Type -import com.fasterxml.jackson.annotation.{JsonProperty, JsonSubTypes, JsonTypeInfo} -import xyz.driver.core.auth.User -import xyz.driver.entities.assays.PatientCase -import xyz.driver.entities.clinic.ClinicalRecord -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.utils.Utils -import xyz.driver.pdsuidomain.entities.MedicalRecord.Meta -import xyz.driver.pdsuidomain.entities.MedicalRecord.Meta.{Duplicate, Reorder, Rotation} - -object MedicalRecord { - - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") - @JsonSubTypes( - Array( - new Type(value = classOf[Duplicate], name = "duplicate"), - new Type(value = classOf[Reorder], name = "reorder"), - new Type(value = classOf[Rotation], name = "rotation") - )) - trait Meta { - @JsonProperty("type") def metaType: String - } - - object Meta { - - final case class Duplicate(startPage: Double, - endPage: Double, - startOriginalPage: Double, - endOriginalPage: Option[Double]) - extends Meta { - override val metaType = "duplicate" - } - - object Duplicate { - implicit def toPhiString(x: Duplicate): PhiString = { - import x._ - phi"Duplicate(startPage=${Unsafe(startPage)}, endPage=${Unsafe(endPage)}, " + - phi"startOriginalPage=${Unsafe(startOriginalPage)}, endOriginalPage=${Unsafe(endOriginalPage)}" - } - } - - final case class Reorder(items: Seq[Int]) extends Meta { - override val metaType = "reorder" - } - - object Reorder { - implicit def toPhiString(x: Reorder): PhiString = { - import x._ - phi"Reorder(items=${Unsafe(items.toString)})" - } - } - - final case class Rotation(items: Map[String, Int]) extends Meta { - override val metaType = "rotation" - } - - object Rotation { - implicit def toPhiString(x: Rotation): PhiString = { - import x._ - phi"Rotation(items=${Unsafe(items.toString)})" - } - } - - implicit def toPhiString(input: Meta): PhiString = input match { - case x: Duplicate => Duplicate.toPhiString(x) - case x: Reorder => Reorder.toPhiString(x) - case x: Rotation => Rotation.toPhiString(x) - } - - } - - // Product with Serializable fixes issue: - // Set(New, Cleaned) has type Set[Status with Product with Serializable] - sealed trait Status extends Product with Serializable { - - def oneOf(xs: Status*): Boolean = xs.contains(this) - - def oneOf(xs: Set[Status]): Boolean = xs.contains(this) - - } - object Status { - case object New extends Status - case object Cleaned extends Status - case object Reviewed extends Status - case object Organized extends Status - case object Done extends Status - case object Flagged extends Status - case object Archived extends Status - - def fromString(status: String): Option[Status] = status match { - case "New" => Some(New) - case "Cleaned" => Some(Cleaned) - case "Reviewed" => Some(Reviewed) - case "Organized" => Some(Organized) - case "Done" => Some(Done) - case "Flagged" => Some(Flagged) - case "Archived" => Some(Archived) - case _ => None - } - - val All: Set[Status] = Set[Status]( - New, - Cleaned, - Reviewed, - Organized, - Done, - Flagged, - Archived - ) - - val AllPrevious: Set[Status] = Set[Status](New, Cleaned, Reviewed, Organized) - - implicit def toPhiString(x: Status): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) - } - - sealed trait PdfSource - - object PdfSource { - case object Empty extends PdfSource - - /** @param createResource Constructor of the resource which is represents the file */ - final case class Channel(createResource: () => ReadableByteChannel) extends PdfSource - } - - implicit def toPhiString(x: MedicalRecord): PhiString = { - import x._ - phi"MedicalRecord(id=$id, status=$status, assignee=${Unsafe(assignee)}, " + - phi"previousAssignee=${Unsafe(previousAssignee)}, lastActiveUserId=${Unsafe(lastActiveUserId)})" - } -} - -final case class MedicalRecord(id: LongId[MedicalRecord], - status: MedicalRecord.Status, - previousStatus: Option[MedicalRecord.Status], - assignee: Option[xyz.driver.core.Id[User]], - previousAssignee: Option[xyz.driver.core.Id[User]], - lastActiveUserId: Option[xyz.driver.core.Id[User]], - patientId: UuidId[Patient], - requestId: xyz.driver.core.Id[ClinicalRecord], - disease: String, - caseId: Option[xyz.driver.core.Id[PatientCase]], - physician: Option[String], - meta: Option[TextJson[List[Meta]]], - lastUpdate: LocalDateTime, - totalPages: Int) { - - import MedicalRecord.Status._ - - if (previousStatus.nonEmpty) { - assert(AllPrevious.contains(previousStatus.get), s"Previous status has invalid value: ${previousStatus.get}") - } - - // TODO: with the current business logic code this constraint sometimes harmful - // require(status match { - // case MedicalRecord.Status.Done if assignee.isDefined => false - // case _ => true - // }, "Assignee can't be defined in Done status") -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordHistory.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordHistory.scala deleted file mode 100644 index 5ed5805..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordHistory.scala +++ /dev/null @@ -1,112 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.{LocalDateTime, ZoneId} - -import xyz.driver.core.auth.User -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.utils.Utils -import xyz.driver.pdsuidomain.entities.MedicalRecordHistory._ - -object MedicalRecordHistory { - - implicit def toPhiString(x: MedicalRecordHistory): PhiString = { - import x._ - phi"MedicalRecordHistory(id=$id, executor=${Unsafe(executor)}, recordId=$recordId, state=$state, action=$action, " + - phi"created=$created)" - } - - sealed trait State - - object State { - case object New extends State - case object Clean extends State - case object Organize extends State - case object Review extends State - case object Done extends State - case object Flag extends State - case object Archive extends State - - val All: Set[State] = Set( - State.New, - State.Clean, - State.Organize, - State.Review, - State.Done, - State.Flag, - State.Archive - ) - - private val stateToName: Map[State, String] = - All.map(s => s -> s.toString).toMap - - val fromString: PartialFunction[String, State] = - for ((k, v) <- stateToName) yield (v, k) - - def stateToString: State => String = stateToName - - implicit def toPhiString(x: State): PhiString = - Unsafe(Utils.getClassSimpleName(x.getClass)) - } - - sealed trait Action extends Product with Serializable { - def oneOf(xs: Action*): Boolean = xs.contains(this) - def oneOf(xs: Set[Action]): Boolean = xs.contains(this) - } - - object Action { - case object Start extends Action - case object Submit extends Action - case object Unassign extends Action - case object Resolve extends Action - case object Flag extends Action - case object Archive extends Action - case object SaveDuplicate extends Action - case object SaveReorder extends Action - case object SaveRotation extends Action - case object DeleteDuplicate extends Action - case object DeleteReorder extends Action - case object DeleteRotation extends Action - case object CreateDocument extends Action - case object DeleteDocument extends Action - case object CreateRecord extends Action - case object ReadRecord extends Action - - val All: Set[Action] = Set( - Action.Start, - Action.Submit, - Action.Unassign, - Action.Resolve, - Action.Flag, - Action.Archive, - Action.SaveDuplicate, - Action.SaveReorder, - Action.SaveRotation, - Action.DeleteDuplicate, - Action.DeleteReorder, - Action.DeleteRotation, - Action.CreateDocument, - Action.DeleteDocument, - Action.CreateRecord, - Action.ReadRecord - ) - - private val actionToName: Map[Action, String] = - All.map(a => a -> a.toString).toMap - - val fromString: PartialFunction[String, Action] = - for ((k, v) <- actionToName) yield (v, k) - - def actionToString: Action => String = actionToName - - implicit def toPhiString(x: Action): PhiString = - Unsafe(Utils.getClassSimpleName(x.getClass)) - } -} - -final case class MedicalRecordHistory(id: LongId[MedicalRecordHistory], - executor: xyz.driver.core.Id[User], - recordId: LongId[MedicalRecord], - state: State, - action: Action, - created: LocalDateTime = LocalDateTime.now(ZoneId.of("Z"))) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordIssue.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordIssue.scala deleted file mode 100644 index 6cdad49..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordIssue.scala +++ /dev/null @@ -1,24 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDateTime - -import xyz.driver.core.auth.User -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.logging._ - -final case class MedicalRecordIssue(id: LongId[MedicalRecordIssue], - userId: xyz.driver.core.Id[User], - recordId: LongId[MedicalRecord], - startPage: Option[Double], - endPage: Option[Double], - lastUpdate: LocalDateTime, - isDraft: Boolean, - text: String, - archiveRequired: Boolean) - -object MedicalRecordIssue { - implicit def toPhiString(x: MedicalRecordIssue): PhiString = { - import x._ - phi"MedicalRecordIssue(id=$id, userId=${Unsafe(userId)}, recordId=$recordId)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Message.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Message.scala deleted file mode 100644 index 68fd5cd..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/Message.scala +++ /dev/null @@ -1,35 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDateTime - -import xyz.driver.core.auth.User -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} -import xyz.driver.pdsuicommon.logging._ - -final case class Message(id: LongId[Message], - text: String, - lastUpdate: LocalDateTime, - userId: xyz.driver.core.Id[User], - isDraft: Boolean, - recordId: Option[LongId[MedicalRecord]], - documentId: Option[LongId[Document]], - patientId: Option[UuidId[Patient]], - trialId: Option[StringId[Trial]], - startPage: Option[Double], - endPage: Option[Double], - evidence: Option[String], - archiveRequired: Option[Boolean], - meta: Option[String]) - -object Message { - implicit def toPhiString(x: Message): PhiString = { - import x._ - - val entityId: Option[String] = recordId - .map(_.toString) - .orElse(documentId.map(_.toString)) - .orElse(patientId.map(_.toString)) - - phi"Message(id=$id, userId=${Unsafe(userId)}, isDraft=$isDraft, entityId=${Unsafe(entityId)}" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Patient.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Patient.scala deleted file mode 100644 index c48e0d9..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/Patient.scala +++ /dev/null @@ -1,63 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.{LocalDate, LocalDateTime} - -import xyz.driver.core.auth.User -import xyz.driver.entities.clinic.TestOrder -import xyz.driver.entities.common.FullName -import xyz.driver.entities.patient.CancerType -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.utils.Utils - -object Patient { - - // Product with Serizalizable fixes issue: - // Set(New, Verified) has type Set[Status with Product with Serializable] - sealed trait Status extends Product with Serializable { - def oneOf(xs: Status*): Boolean = xs.contains(this) - - def oneOf(xs: Set[Status]): Boolean = xs.contains(this) - } - - object Status { - case object New extends Status - case object Verified extends Status - case object Reviewed extends Status - case object Curated extends Status - case object Flagged extends Status - case object Done extends Status - - val AllPrevious: Set[Status] = Set[Status](New, Verified, Reviewed, Curated) - - val All: Set[Status] = Set[Status](New, Verified, Reviewed, Curated, Flagged, Done) - - implicit def toPhiString(x: Status): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) - } - - implicit def toPhiString(x: Patient): PhiString = { - import x._ - phi"Patient(id=$id, status=$status, previousStatus=$previousStatus, lastActiveUserId=${Unsafe(lastActiveUserId)}" + - phi"assignee=${Unsafe(assignee)}, previousAssignee=${Unsafe(previousAssignee)})" - } -} - -final case class Patient(id: UuidId[Patient], - status: Patient.Status, - name: FullName[Patient], - dob: LocalDate, - assignee: Option[xyz.driver.core.Id[User]], - previousStatus: Option[Patient.Status], - previousAssignee: Option[xyz.driver.core.Id[User]], - lastActiveUserId: Option[xyz.driver.core.Id[User]], - isUpdateRequired: Boolean, - disease: CancerType, - orderId: xyz.driver.core.Id[TestOrder], - lastUpdate: LocalDateTime) { - - import Patient.Status._ - - if (previousStatus.nonEmpty) { - assert(AllPrevious.contains(previousStatus.get), s"Previous status has invalid value: ${previousStatus.get}") - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientCriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientCriterion.scala deleted file mode 100644 index e6d466a..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientCriterion.scala +++ /dev/null @@ -1,96 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDateTime - -import xyz.driver.entities.labels.{Label, LabelValue} -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuicommon.logging._ - -object PatientCriterion { - implicit def toPhiString(x: PatientCriterion): PhiString = { - import x._ - phi"PatientCriterion(id=$id, patientLabelId=$patientLabelId, trialId=${Unsafe(trialId)}, nctId=$nctId, " + - phi"criterionId=$criterionId, criterionValue=${Unsafe(criterionValue)}, " + - phi"isImplicitMatch=$criterionIsDefining), criterionIsDefining=${Unsafe(criterionIsDefining)}, " + - phi"eligibilityStatus=${Unsafe(eligibilityStatus)}, verifiedEligibilityStatus=${Unsafe(verifiedEligibilityStatus)}, " + - phi"isVerified=${Unsafe(isVerified)}, lastUpdate=${Unsafe(lastUpdate)}, inclusion=${Unsafe(inclusion)}" - } - - /** - * @see https://driverinc.atlassian.net/wiki/display/MTCH/EV+Business+Process - */ - def getEligibilityStatus(criterionValue: Option[Boolean], primaryValue: LabelValue): LabelValue = { - primaryValue match { - case LabelValue.Unknown => LabelValue.Unknown - case LabelValue.Maybe => LabelValue.Maybe - case _ if criterionValue.isEmpty => LabelValue.Maybe - case status => - LabelValue.fromBoolean( - LabelValue.fromBoolean( - criterionValue.getOrElse(throw new IllegalArgumentException("Criterion should not be empty"))) == status - ) - } - } - -} - -/** - * @param eligibilityStatus - a value, that selects an eligibility verifier (EV) - * @param verifiedEligibilityStatus - a copy of eligibilityStatus, when a patient goes to routes curator (RC) - * @param isVerified - is EV selected the eligibilityStatus? - */ -final case class PatientCriterion(id: LongId[PatientCriterion], - patientLabelId: LongId[PatientLabel], - trialId: Long, - nctId: StringId[Trial], - criterionId: LongId[Criterion], - criterionText: String, - criterionValue: Option[Boolean], - criterionIsDefining: Boolean, - eligibilityStatus: LabelValue, - verifiedEligibilityStatus: LabelValue, - isVerified: Boolean, - isVisible: Boolean, - lastUpdate: LocalDateTime, - inclusion: Option[Boolean]) { - import scalaz.syntax.equal._ - def isIneligibleForEv: Boolean = eligibilityStatus === LabelValue.No && isVerified -} - -final case class DraftPatientCriterion(id: LongId[PatientCriterion], - eligibilityStatus: Option[LabelValue], - isVerified: Option[Boolean]) { - def applyTo(orig: PatientCriterion) = { - orig.copy( - eligibilityStatus = eligibilityStatus.getOrElse(orig.eligibilityStatus), - isVerified = isVerified.getOrElse(orig.isVerified) - ) - } -} - -object DraftPatientCriterion { - implicit def toPhiString(x: DraftPatientCriterion): PhiString = { - phi"DraftPatientCriterion(id=${x.id}, eligibilityStatus=${Unsafe(x.eligibilityStatus)}, isVerified=${x.isVerified})" - } -} - -final case class RichPatientCriterion(patientCriterion: PatientCriterion, - labelId: LongId[Label], - armList: List[PatientCriterionArm]) - -object RichPatientCriterion { - implicit def toPhiString(x: RichPatientCriterion): PhiString = { - phi"RichPatientCriterion(patientCriterion=${x.patientCriterion}, labelId=${x.labelId}, arms=${x.armList})" - } -} - -object PatientCriterionArm { - - implicit def toPhiString(x: PatientCriterionArm): PhiString = { - import x._ - phi"PatientCriterionArm(patientCriterionId=$patientCriterionId, armId=$armId, armName=${Unsafe(armName)})" - } - -} - -final case class PatientCriterionArm(patientCriterionId: LongId[PatientCriterion], armId: LongId[Arm], armName: String) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientEligibleTrial.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientEligibleTrial.scala deleted file mode 100644 index 4f62a9e..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientEligibleTrial.scala +++ /dev/null @@ -1,94 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import xyz.driver.entities.labels.LabelValue -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} -import xyz.driver.pdsuicommon.logging._ - -object PatientTrialArm { - - implicit def toPhiString(x: PatientTrialArm): PhiString = { - import x._ - phi"PatientTrialArm(armId=$armId, trialArmGroupId=$trialArmGroupId)" - } -} - -final case class PatientTrialArm(armId: LongId[Arm], trialArmGroupId: LongId[PatientTrialArmGroup]) - -object PatientEligibleTrial { - implicit def toPhiString(x: PatientEligibleTrial): PhiString = { - import x._ - phi"PatientEligibleTrial(id=$id, patientId=$patientId, trialId=$trialId, hypothesisId=$hypothesisId)" - } -} - -final case class PatientEligibleTrial(id: UuidId[PatientEligibleTrial], - patientId: UuidId[Patient], - trialId: StringId[Trial], - hypothesisId: UuidId[Hypothesis]) - -object PatientTrialArmGroup { - - implicit def toPhiString(x: PatientTrialArmGroup): PhiString = { - import x._ - phi"PatientTrialArmGroup(id=$id, eligibleTrialId=$eligibleTrialId, " + - phi"eligibilityStatus=${Unsafe(eligibilityStatus)}, " + - phi"verifiedEligibilityStatus=${Unsafe(verifiedEligibilityStatus)}, isVerified=$isVerified)" - } - - /** - * @see https://driverinc.atlassian.net/wiki/display/DMPD/EV+Business+Process - */ - def getEligibilityStatusForRc(criterionList: TraversableOnce[PatientCriterion]): LabelValue = { - def isEligible: Boolean = criterionList.forall(_.verifiedEligibilityStatus == LabelValue.Yes) - def isIneligible: Boolean = criterionList.exists(_.verifiedEligibilityStatus == LabelValue.No) - def isUnknown: Boolean = criterionList.forall(_.verifiedEligibilityStatus == LabelValue.Unknown) - - if (isEligible) LabelValue.Yes - else if (isIneligible) LabelValue.No - else if (isUnknown) LabelValue.Unknown - else LabelValue.Maybe - } -} - -final case class PatientTrialArmGroup(id: LongId[PatientTrialArmGroup], - eligibleTrialId: UuidId[PatientEligibleTrial], - eligibilityStatus: LabelValue, - verifiedEligibilityStatus: LabelValue, - isVerified: Boolean) - -object PatientTrialArmGroupView { - - implicit def toPhiString(x: PatientTrialArmGroupView): PhiString = { - import x._ - phi"PatientTrialArmGroupView(id=$id, patientId=$patientId, trialId=$trialId, " + - phi"hypothesisId=$hypothesisId, eligibilityStatus=${Unsafe(eligibilityStatus)}, " + - phi"verifiedEligibilityStatus=${Unsafe(verifiedEligibilityStatus)}, isVerified=$isVerified)" - } -} - -final case class PatientTrialArmGroupView(id: LongId[PatientTrialArmGroup], - patientId: UuidId[Patient], - trialId: StringId[Trial], - hypothesisId: UuidId[Hypothesis], - eligibilityStatus: LabelValue, - verifiedEligibilityStatus: LabelValue, - isVerified: Boolean) { - - def applyTo(trialArmGroup: PatientTrialArmGroup) = { - trialArmGroup.copy( - eligibilityStatus = this.eligibilityStatus, - verifiedEligibilityStatus = this.verifiedEligibilityStatus, - isVerified = this.isVerified - ) - } -} - -final case class RichPatientEligibleTrial(trial: Trial, - group: PatientTrialArmGroupView, - arms: List[PatientCriterionArm]) - -object RichPatientEligibleTrial { - implicit def toPhiString(x: RichPatientEligibleTrial): PhiString = { - phi"RichPatientEligibleTrial(group=${x.group}, trial=${x.trial}, arms=${x.arms})" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientHistory.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientHistory.scala deleted file mode 100644 index bea2c3b..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientHistory.scala +++ /dev/null @@ -1,94 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.{LocalDateTime, ZoneId} - -import xyz.driver.core.auth.User -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.utils.Utils -import xyz.driver.pdsuidomain.entities.PatientHistory.{Action, State} - -object PatientHistory { - - implicit def toPhiString(x: PatientHistory): PhiString = { - import x._ - phi"PatientHistory(id=$id, executor=${Unsafe(executor)}, patientId=$patientId, " + - phi"state=$state, action=$action, created=$created)" - } - - sealed trait State - object State { - case object Verify extends State - case object Curate extends State - case object Review extends State - case object Flag extends State - - val All: Set[State] = Set[State](Verify, Curate, Review, Flag) - - val fromString: PartialFunction[String, State] = { - case "Verify" => State.Verify - case "Curate" => State.Curate - case "Review" => State.Review - case "Flag" => State.Flag - } - - def stateToString(x: State): String = x match { - case State.Verify => "Verify" - case State.Curate => "Curate" - case State.Review => "Review" - case State.Flag => "Flag" - } - - implicit def toPhiString(x: State): PhiString = - Unsafe(Utils.getClassSimpleName(x.getClass)) - } - - sealed trait Action extends Product with Serializable { - - def oneOf(xs: Action*): Boolean = xs.contains(this) - - def oneOf(xs: Set[Action]): Boolean = xs.contains(this) - - } - - object Action { - case object Start extends Action - case object Submit extends Action - case object Unassign extends Action - case object Resolve extends Action - case object Flag extends Action - case object Archive extends Action - - val All: Set[Action] = - Set[Action](Start, Submit, Unassign, Resolve, Flag, Archive) - - val fromString: PartialFunction[String, Action] = { - case "Start" => Action.Start - case "Submit" => Action.Submit - case "Unassign" => Action.Unassign - case "Resolve" => Action.Resolve - case "Flag" => Action.Flag - case "Archive" => Action.Archive - } - - def actionToString(x: Action): String = x match { - case Action.Start => "Start" - case Action.Submit => "Submit" - case Action.Unassign => "Unassign" - case Action.Resolve => "Resolve" - case Action.Flag => "Flag" - case Action.Archive => "Archive" - } - - implicit def toPhiString(x: Action): PhiString = - Unsafe(Utils.getClassSimpleName(x.getClass)) - } - -} - -final case class PatientHistory(id: LongId[PatientHistory], - executor: xyz.driver.core.Id[User], - patientId: UuidId[Patient], - state: State, - action: Action, - created: LocalDateTime = LocalDateTime.now(ZoneId.of("Z"))) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientHypothesis.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientHypothesis.scala deleted file mode 100644 index 7943fb9..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientHypothesis.scala +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import eu.timepit.refined.api.Refined -import eu.timepit.refined.numeric.NonNegative -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuicommon.logging._ - -object PatientHypothesis { - implicit def toPhiString(x: PatientHypothesis): PhiString = { - import x._ - phi"PatientHypothesis(id=$id, patientId=$patientId, hypothesisId=$hypothesisId, " + - phi"rationale=${Unsafe(rationale)}, matchedTrials=${Unsafe(matchedTrials)})" - } -} - -final case class PatientHypothesis(id: UuidId[PatientHypothesis], - patientId: UuidId[Patient], - hypothesisId: UuidId[Hypothesis], - rationale: Option[String], - matchedTrials: Long Refined NonNegative) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientIssue.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientIssue.scala deleted file mode 100644 index b60c2ea..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientIssue.scala +++ /dev/null @@ -1,22 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDateTime - -import xyz.driver.core.auth.User -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ - -final case class PatientIssue(id: LongId[PatientIssue], - userId: xyz.driver.core.Id[User], - patientId: UuidId[Patient], - lastUpdate: LocalDateTime, - isDraft: Boolean, - text: String, - archiveRequired: Boolean) - -object PatientIssue { - implicit def toPhiString(x: PatientIssue): PhiString = { - import x._ - phi"PatientIssue(id=$id, userId=${Unsafe(userId)}, patientId=$patientId)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientLabel.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientLabel.scala deleted file mode 100644 index 8d64389..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientLabel.scala +++ /dev/null @@ -1,47 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import xyz.driver.entities.labels.{Label, LabelValue} -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuicommon.logging._ - -object PatientLabel { - implicit def toPhiString(x: PatientLabel): PhiString = { - import x._ - phi"PatientLabel(id=$id, patientId=$patientId, labelId=$labelId, " + - phi"score=${Unsafe(score)}, primaryValue=${Unsafe(primaryValue)}, " + - phi"verifiedPrimaryValue=${Unsafe(verifiedPrimaryValue)})" - } -} - -final case class PatientLabel(id: LongId[PatientLabel], - patientId: UuidId[Patient], - labelId: LongId[Label], - score: Int, - primaryValue: LabelValue, - verifiedPrimaryValue: LabelValue, - isImplicitMatch: Boolean, - isVisible: Boolean) - -final case class RichPatientLabel(patientLabel: PatientLabel, isVerified: Boolean) - -object RichPatientLabel { - implicit def toPhiString(x: RichPatientLabel): PhiString = { - phi"RichPatientLabel(patientLabel=${x.patientLabel}, isVerified=${x.isVerified})" - } -} - -object PatientLabelEvidence { - implicit def toPhiString(x: PatientLabelEvidence): PhiString = { - import x._ - phi"PatientLabelEvidence(id=$id, patientLabelId=$patientLabelId, value=${Unsafe(value)}, " + - phi"documentId=$documentId, evidenceId=$evidenceId, reportId=$reportId)" - } -} - -final case class PatientLabelEvidence(id: LongId[PatientLabelEvidence], - patientLabelId: LongId[PatientLabel], - value: LabelValue, - evidenceText: String, - reportId: Option[UuidId[DirectReport]], - documentId: Option[LongId[Document]], - evidenceId: Option[LongId[ExtractedData]]) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientLabelEvidenceView.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientLabelEvidenceView.scala deleted file mode 100644 index 6055921..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientLabelEvidenceView.scala +++ /dev/null @@ -1,29 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDate - -import xyz.driver.entities.labels.{Label, LabelValue} -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ - -object PatientLabelEvidenceView { - implicit def toPhiString(x: PatientLabelEvidenceView): PhiString = { - import x._ - phi"PatientLabelEvidenceView(id=$id, value=${Unsafe(value)}, documentId=$documentId, " + - phi"evidenceId=$evidenceId, reportId=$reportId, patientId=$patientId, labelId=$labelId, " + - phi"isImplicitMatch=$isImplicitMatch)" - } -} - -final case class PatientLabelEvidenceView(id: LongId[PatientLabelEvidence], - value: LabelValue, - evidenceText: String, - documentId: Option[LongId[Document]], - evidenceId: Option[LongId[ExtractedData]], - reportId: Option[UuidId[DirectReport]], - documentType: DocumentType, - date: Option[LocalDate], // Document.startDate is optional - providerType: ProviderType, - patientId: UuidId[Patient], - labelId: LongId[Label], - isImplicitMatch: Boolean) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/RawPatientDocument.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/RawPatientDocument.scala deleted file mode 100644 index 45cdc4e..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/RawPatientDocument.scala +++ /dev/null @@ -1,30 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDate - -import xyz.driver.core.Id -import xyz.driver.entities.clinic.ClinicalRecord -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuicommon.logging._ - -final case class RawPatientDocument(disease: String, - patientId: UuidId[Patient], - requestId: Id[ClinicalRecord], - recordId: LongId[MedicalRecord], - recordStatus: MedicalRecord.Status, - documentId: LongId[Document], - documentType: String, - documentProviderType: String, - documentStartDate: LocalDate, - documentStatus: Document.Status) - -object RawPatientDocument { - - implicit def toPhiString(x: RawPatientDocument): PhiString = { - import x._ - phi"RawPatientDocument(disease=${Unsafe(disease)}, patientId=$patientId, requestId=${Unsafe(requestId)}, " + - phi"recordId=$recordId, recordStatus=$recordStatus, documentId=$documentId, " + - phi"documentType=${Unsafe(documentType)}, providerType=${Unsafe(documentProviderType)}, " + - phi"startDate=$documentStartDate, documentStatus=$documentStatus)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArmEligibilityArm.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArmEligibilityArm.scala deleted file mode 100644 index 70114de..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArmEligibilityArm.scala +++ /dev/null @@ -1,13 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.logging._ - -final case class SlotArmEligibilityArm(slotArmId: LongId[SlotArm], eligibilityArmId: LongId[EligibilityArm]) - -object SlotArmEligibilityArm { - implicit def toPhiString(x: SlotArmEligibilityArm): PhiString = { - import x._ - phi"SlotArmEligibilityArm(slotArmId=$slotArmId, eligibilityArmId=$eligibilityArmId)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArms.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArms.scala deleted file mode 100644 index 932de38..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArms.scala +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDateTime - -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuicommon.logging._ - -final case class SlotArm(id: LongId[SlotArm], - name: String, - originalName: String, - trialId: StringId[Trial], - deleted: Option[LocalDateTime] = None) - -object SlotArm { - - implicit def toPhiString(x: SlotArm): PhiString = { - import x._ - phi"Arm(id=$id, name=${Unsafe(x.name)}, trialId=${Unsafe(x.trialId)})" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala deleted file mode 100644 index fa5ed61..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala +++ /dev/null @@ -1,126 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDateTime - -import xyz.driver.core.auth.User -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.utils.Utils -import xyz.driver.pdsuidomain.entities.Trial.Status - -import scalaz.syntax.equal._ -import scalaz.Scalaz.stringInstance - -sealed trait StudyDesign { - val id: LongId[StudyDesign] - val name: String -} - -object StudyDesign { - - final case object Randomized extends StudyDesign { - val id: LongId[StudyDesign] = LongId[StudyDesign](1) - val name: String = "Randomized" - } - - final case object NonRandomized extends StudyDesign { - val id: LongId[StudyDesign] = LongId[StudyDesign](2) - val name: String = "Non-randomized" - } - - final case object SingleGroupAssignment extends StudyDesign { - val id: LongId[StudyDesign] = LongId[StudyDesign](3) - val name: String = "Single-group assignment" - } - - val All = Seq[StudyDesign]( - Randomized, - NonRandomized, - SingleGroupAssignment - ) - - def fromString(txt: String): Option[StudyDesign] = { - All.find(_.name === txt) - } - - implicit def toPhiString(x: StudyDesign): PhiString = { - import x._ - phi"StudyDesign(id=$id, category=${Unsafe(name)})" - } -} - -object TrialCreationRequest { - - implicit def toPhiString(x: TrialCreationRequest): PhiString = phi"${Unsafe(x.toString)}" -} - -final case class TrialCreationRequest(id: UuidId[Trial], nctId: String, phase: String) - -object Trial { - - sealed trait Status { - def oneOf(xs: Status*): Boolean = xs.contains(this) - def oneOf(xs: Set[Status]): Boolean = xs.contains(this) - } - - object Status { - case object New extends Status - case object ReviewSummary extends Status - case object Summarized extends Status - case object PendingUpdate extends Status - case object Update extends Status - case object ReviewCriteria extends Status - case object Done extends Status - case object Flagged extends Status - case object Archived extends Status - - val All: Set[Status] = Set[Status]( - New, - ReviewSummary, - Summarized, - PendingUpdate, - Update, - ReviewCriteria, - Done, - Flagged, - Archived - ) - - val AllPrevious: Set[Status] = Set[Status](New, ReviewSummary, Summarized, ReviewCriteria) - - implicit def toPhiString(x: Status): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) - } - - implicit def toPhiString(x: Trial): PhiString = { - import x._ - phi"Trial(id=$id, externalId=$externalId, status=$status, previousStatus=$previousStatus, " + - phi"lastActiveUserId=${Unsafe(lastActiveUserId)}, assignee=${Unsafe(assignee)}, previousAssignee=${Unsafe(previousAssignee)})" - } - - final case class Locations(locations: List[String]) -} - -final case class Trial(id: StringId[Trial], - externalId: UuidId[Trial], - status: Status, - assignee: Option[xyz.driver.core.Id[User]], - previousStatus: Option[Status], - previousAssignee: Option[xyz.driver.core.Id[User]], - lastActiveUserId: Option[xyz.driver.core.Id[User]], - lastUpdate: LocalDateTime, - phase: String, - hypothesisId: Option[UuidId[Hypothesis]], - studyDesignId: Option[LongId[StudyDesign]], - originalStudyDesign: Option[String], - isPartner: Boolean, - overview: Option[String], - overviewTemplate: String, - isUpdated: Boolean, - title: String, - originalTitle: String) { - import Trial.Status._ - - if (previousStatus.nonEmpty) { - assert(AllPrevious.contains(previousStatus.get), s"Previous status has invalid value: ${previousStatus.get}") - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/TrialHistory.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/TrialHistory.scala deleted file mode 100644 index 9210742..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/TrialHistory.scala +++ /dev/null @@ -1,100 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.{LocalDateTime, ZoneId} - -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.utils.Utils -import TrialHistory._ -import xyz.driver.core.auth.User - -object TrialHistory { - - implicit def toPhiString(x: TrialHistory): PhiString = { - import x._ - phi"TrialHistory(id=$id, executor=${Unsafe(executor)}, trialId=$trialId, state=$state, action=$action, created=$created)" - } - - sealed trait State - object State { - case object Summarize extends State - case object Criteriarize extends State - case object Review extends State - case object ReviewSummary extends State - case object ReviewCriteria extends State - case object Flag extends State - - val All: Set[State] = Set[State](Summarize, Criteriarize, Review, ReviewSummary, ReviewCriteria, Flag) - - val fromString: PartialFunction[String, State] = { - case "Summarize" => State.Summarize - case "Criteriarize" => State.Criteriarize - case "Review" => State.Review - case "ReviewSummary" => State.ReviewSummary - case "ReviewCriteria" => State.ReviewCriteria - case "Flag" => State.Flag - } - - def stateToString(x: State): String = x match { - case State.Summarize => "Summarize" - case State.Criteriarize => "Criteriarize" - case State.Review => "Review" - case State.ReviewSummary => "ReviewSummary" - case State.ReviewCriteria => "ReviewCriteria" - case State.Flag => "Flag" - } - - implicit def toPhiString(x: State): PhiString = - Unsafe(Utils.getClassSimpleName(x.getClass)) - } - - sealed trait Action extends Product with Serializable { - - def oneOf(xs: Action*): Boolean = xs.contains(this) - - def oneOf(xs: Set[Action]): Boolean = xs.contains(this) - - } - - object Action { - case object Start extends Action - case object Submit extends Action - case object Unassign extends Action - case object Resolve extends Action - case object Flag extends Action - case object Archive extends Action - - val All: Set[Action] = - Set[Action](Start, Submit, Unassign, Resolve, Flag, Archive) - - val fromString: PartialFunction[String, Action] = { - case "Start" => Action.Start - case "Submit" => Action.Submit - case "Unassign" => Action.Unassign - case "Resolve" => Action.Resolve - case "Flag" => Action.Flag - case "Archive" => Action.Archive - } - - def actionToString(x: Action): String = x match { - case Action.Start => "Start" - case Action.Submit => "Submit" - case Action.Unassign => "Unassign" - case Action.Resolve => "Resolve" - case Action.Flag => "Flag" - case Action.Archive => "Archive" - } - - implicit def toPhiString(x: Action): PhiString = - Unsafe(Utils.getClassSimpleName(x.getClass)) - } - -} - -final case class TrialHistory(id: LongId[TrialHistory], - executor: xyz.driver.core.Id[User], - trialId: StringId[Trial], - state: State, - action: Action, - created: LocalDateTime = LocalDateTime.now(ZoneId.of("Z")), - comment: Option[String] = None) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/TrialIssue.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/TrialIssue.scala deleted file mode 100644 index f69e681..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/TrialIssue.scala +++ /dev/null @@ -1,24 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.LocalDateTime - -import xyz.driver.core.auth.User -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuicommon.logging._ - -final case class TrialIssue(id: LongId[TrialIssue], - userId: xyz.driver.core.Id[User], - trialId: StringId[Trial], - lastUpdate: LocalDateTime, - isDraft: Boolean, - text: String, - evidence: String, - archiveRequired: Boolean, - meta: String) - -object TrialIssue { - implicit def toPhiString(x: TrialIssue): PhiString = { - import x._ - phi"TrialIssue(id=$id, userId=${Unsafe(userId)}, trialId=$trialId)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/UserHistory.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/UserHistory.scala deleted file mode 100644 index 6299ed4..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/UserHistory.scala +++ /dev/null @@ -1,146 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import java.time.{LocalDateTime, ZoneId} - -import xyz.driver.core.auth.User -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuicommon.utils.Utils - -final case class UserHistory(id: LongId[UserHistory], - executor: xyz.driver.core.Id[User], - recordId: Option[LongId[MedicalRecord]] = None, - documentId: Option[LongId[Document]] = None, - trialId: Option[StringId[Trial]] = None, - patientId: Option[UuidId[Patient]] = None, - state: UserHistory.State, - action: UserHistory.Action, - created: LocalDateTime = LocalDateTime.now(ZoneId.of("Z"))) - -object UserHistory { - - def forDocument(executor: xyz.driver.core.Id[User], - documentId: LongId[Document], - state: UserHistory.State, - action: UserHistory.Action): UserHistory = UserHistory( - id = LongId(0L), - executor = executor, - documentId = Some(documentId), - state = state, - action = action - ) - - def forRecord(executor: xyz.driver.core.Id[User], - recordId: LongId[MedicalRecord], - state: UserHistory.State, - action: UserHistory.Action): UserHistory = UserHistory( - id = LongId(0L), - executor = executor, - recordId = Some(recordId), - state = state, - action = action - ) - - def forPatient(executor: xyz.driver.core.Id[User], - patientId: UuidId[Patient], - state: UserHistory.State, - action: UserHistory.Action): UserHistory = UserHistory( - id = LongId(0L), - executor = executor, - patientId = Some(patientId), - state = state, - action = action - ) - - sealed trait State extends Product with Serializable { - - def oneOf(xs: State*): Boolean = xs.contains(this) - - def oneOf(xs: Set[State]): Boolean = xs.contains(this) - } - - object State { - case object Clean extends State - case object Organize extends State - case object Extract extends State - case object Summarize extends State - case object Criteriarize extends State - case object Verify extends State - case object Curate extends State - case object Review extends State - case object Flag extends State - - val All: Set[State] = Set[State](Clean, Organize, Extract, Summarize, Criteriarize, Verify, Curate, Review, Flag) - - val fromString: PartialFunction[String, State] = { - case "Clean" => State.Clean - case "Organize" => State.Organize - case "Extract" => State.Extract - case "Summarize" => State.Summarize - case "Criteriarize" => State.Criteriarize - case "Verify" => State.Verify - case "Curate" => State.Curate - case "Review" => State.Review - case "Flag" => State.Flag - } - - def stateToString(x: State): String = x match { - case State.Clean => "Clean" - case State.Organize => "Organize" - case State.Extract => "Extract" - case State.Summarize => "Summarize" - case State.Criteriarize => "Criteriarize" - case State.Verify => "Verify" - case State.Curate => "Curate" - case State.Review => "Review" - case State.Flag => "Flag" - } - - implicit def toPhiString(x: State): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) - } - - sealed trait Action extends Product with Serializable { - - def oneOf(xs: Action*): Boolean = xs.contains(this) - - def oneOf(xs: Set[Action]): Boolean = xs.contains(this) - } - - object Action { - case object Start extends Action - case object Submit extends Action - case object Unassign extends Action - case object Resolve extends Action - case object Flag extends Action - case object Archive extends Action - - val All: Set[Action] = Set[Action](Start, Submit, Unassign, Resolve, Flag, Archive) - - val fromString: PartialFunction[String, Action] = { - case "Start" => Action.Start - case "Submit" => Action.Submit - case "Unassign" => Action.Unassign - case "Resolve" => Action.Resolve - case "Flag" => Action.Flag - case "Archive" => Action.Archive - } - - def actionToString(x: Action): String = x match { - case Action.Start => "Start" - case Action.Submit => "Submit" - case Action.Unassign => "Unassign" - case Action.Resolve => "Resolve" - case Action.Flag => "Flag" - case Action.Archive => "Archive" - } - - implicit def toPhiString(x: Action): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) - } - - implicit def toPhiString(x: UserHistory): PhiString = { - import x._ - phi"UserHistory(id=$id, executor=${Unsafe(executor)}, recordId=$recordId, " + - phi"documentId=$documentId, trialId=$trialId, patientId=$patientId, " + - phi"state=$state, action=$action, created=$created)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/eligibility.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/eligibility.scala deleted file mode 100644 index 9362a0c..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/eligibility.scala +++ /dev/null @@ -1,68 +0,0 @@ -package xyz.driver.pdsuidomain.entities - -import xyz.driver.core.Id -import xyz.driver.core.date.Date -import xyz.driver.entities.assays.AssayType -import xyz.driver.entities.clinic.{ClinicalRecord, TestOrder} -import xyz.driver.entities.common.FullName -import xyz.driver.entities.labels.{Label, LabelValue} -import xyz.driver.entities.patient.CancerType -import xyz.driver.entities.process.ProcessStepExecutionStatus -import xyz.driver.entities.report.Report -import xyz.driver.pdsuidomain.entities.export.trial.ExportTrialWithLabels - -object eligibility { - - sealed trait EvidenceDocument { - val documentType: DocumentType - val providerType: ProviderType - val providerName: Option[String] - val date: Option[Date] - val isDriverDocument: Boolean - } - - final case class MolecularEvidenceDocument(documentType: DocumentType, - providerType: ProviderType, - providerName: Option[String], - date: Option[Date], - reportId: Id[Report], - reportType: AssayType, - isDriverDocument: Boolean = true) - extends EvidenceDocument - - final case class ClinicalEvidenceDocument(documentId: Id[ClinicalEvidenceDocument], - documentType: DocumentType, - providerType: ProviderType, - providerName: Option[String], - date: Option[Date], - requestId: Id[ClinicalRecord], - isDriverDocument: Boolean = false) - extends EvidenceDocument - - // Some fields are optional because they are not in the backend response - final case class Evidence(evidenceId: Option[Id[Evidence]], - evidenceText: String, - labelValue: LabelValue, - document: EvidenceDocument, - isPrimaryValue: Option[Boolean] = None) - - final case class LabelEvidence(label: Label, evidence: Seq[Evidence] = Seq.empty) - - final case class LabelMismatchRank(label: Label, - score: Int, - trials: Seq[ExportTrialWithLabels], - evidence: Seq[Evidence]) - final case class MismatchRankedLabels(data: Seq[LabelMismatchRank], labelVersion: Int) - - final case class MatchedPatient(patientId: Id[xyz.driver.entities.patient.Patient], - name: FullName[xyz.driver.entities.patient.Patient], - birthDate: Date, - orderId: Id[TestOrder], - disease: CancerType, - patientDataStatus: ProcessStepExecutionStatus) - - final case class EligibleTrial(nctId: String, arms: Seq[EligibleArm]) - final case class EligibleArm(title: String, criteria: Seq[EligibleCriterion]) - final case class EligibleCriterion(text: String, eligibilityStatus: LabelValue) - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabel.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabel.scala deleted file mode 100644 index 957e607..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabel.scala +++ /dev/null @@ -1,15 +0,0 @@ -package xyz.driver.pdsuidomain.entities.export.patient - -import xyz.driver.entities.labels.Label -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.logging._ - -final case class ExportPatientLabel(id: LongId[Label], evidences: List[ExportPatientLabelEvidence]) - -object ExportPatientLabel extends PhiLogging { - - implicit def toPhiString(x: ExportPatientLabel): PhiString = { - import x._ - phi"ExportPatientLabel(id=$id, evidences=$evidences)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidence.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidence.scala deleted file mode 100644 index 6472a6b..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidence.scala +++ /dev/null @@ -1,21 +0,0 @@ -package xyz.driver.pdsuidomain.entities.export.patient - -import xyz.driver.entities.labels.LabelValue -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.ExtractedData - -final case class ExportPatientLabelEvidence(id: LongId[ExtractedData], - value: LabelValue, - evidenceText: String, - document: ExportPatientLabelEvidenceDocument) - -object ExportPatientLabelEvidence { - - implicit def toPhiString(x: ExportPatientLabelEvidence): PhiString = { - import x._ - phi"ExportPatientLabelEvidence(id=${Unsafe(id)}, value=${Unsafe(value)}, " + - phi"evidenceText=${Unsafe(evidenceText)}, document=$document)" - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidenceDocument.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidenceDocument.scala deleted file mode 100644 index 1b3a6d6..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidenceDocument.scala +++ /dev/null @@ -1,23 +0,0 @@ -package xyz.driver.pdsuidomain.entities.export.patient - -import java.time.LocalDate - -import xyz.driver.entities.clinic.ClinicalRecord -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities._ - -final case class ExportPatientLabelEvidenceDocument(documentId: LongId[Document], - requestId: xyz.driver.core.Id[ClinicalRecord], - documentType: DocumentType, - providerType: ProviderType, - date: LocalDate) - -object ExportPatientLabelEvidenceDocument extends PhiLogging { - - implicit def toPhiString(x: ExportPatientLabelEvidenceDocument): PhiString = { - import x._ - phi"ExportPatientLabelEvidenceDocument(documentId=$documentId, requestId=${Unsafe(requestId)}, " + - phi"documentType=${Unsafe(documentType)}, providerType=${Unsafe(providerType)}, date=$date)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientWithLabels.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientWithLabels.scala deleted file mode 100644 index 8fb2660..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientWithLabels.scala +++ /dev/null @@ -1,17 +0,0 @@ -package xyz.driver.pdsuidomain.entities.export.patient - -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.Patient - -final case class ExportPatientWithLabels(patientId: UuidId[Patient], - labelVersion: Long, - labels: List[ExportPatientLabel]) - -object ExportPatientWithLabels { - - implicit def toPhiString(x: ExportPatientWithLabels): PhiString = { - import x._ - phi"ExportPatientWithLabels(patientId=$patientId, version=${Unsafe(labelVersion)}, labels=$labels)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala deleted file mode 100644 index fbac0df..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala +++ /dev/null @@ -1,15 +0,0 @@ -package xyz.driver.pdsuidomain.entities.export.trial - -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.EligibilityArm - -final case class ExportTrialArm(armId: LongId[EligibilityArm], armName: String, diseaseList: Seq[String]) - -object ExportTrialArm { - - implicit def toPhiString(x: ExportTrialArm): PhiString = { - import x._ - phi"ExportTrialArm(armId=$armId, armName=${Unsafe(armName)}, diseaseList=${Unsafe(diseaseList)})" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala deleted file mode 100644 index 98bd084..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala +++ /dev/null @@ -1,24 +0,0 @@ -package xyz.driver.pdsuidomain.entities.export.trial - -import xyz.driver.entities.labels.Label -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.{Criterion, EligibilityArm} - -final case class ExportTrialLabelCriterion(criterionId: LongId[Criterion], - value: Option[Boolean], - labelId: LongId[Label], - armIds: Set[LongId[EligibilityArm]], - criteria: String, - isCompound: Boolean, - isDefining: Boolean, - inclusion: Option[Boolean]) - -object ExportTrialLabelCriterion { - - implicit def toPhiString(x: ExportTrialLabelCriterion): PhiString = { - import x._ - phi"TrialLabelCriterion(criterionId=$criterionId, value=$value, labelId=$labelId, " + - phi"criteria=${Unsafe(criteria)}, isCompound=$isCompound, isDefining=$isDefining), inclusion=${Unsafe(inclusion)}" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala deleted file mode 100644 index 3681945..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala +++ /dev/null @@ -1,23 +0,0 @@ -package xyz.driver.pdsuidomain.entities.export.trial - -import java.time.LocalDateTime - -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.Trial - -final case class ExportTrialWithLabels(nctId: StringId[Trial], - trialId: UuidId[Trial], - lastReviewed: LocalDateTime, - labelVersion: Long, - arms: List[ExportTrialArm], - criteria: List[ExportTrialLabelCriterion]) - -object ExportTrialWithLabels { - - implicit def toPhiString(x: ExportTrialWithLabels): PhiString = { - import x._ - phi"TrialWithLabels(nctId=$nctId, trialId=$trialId}, " + - phi"lastReviewed=$lastReviewed, labelVersion=${Unsafe(labelVersion)}, arms=$arms, criteria=$criteria)" - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/common.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/common.scala deleted file mode 100644 index 2aaa251..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/common.scala +++ /dev/null @@ -1,123 +0,0 @@ -package xyz.driver.pdsuidomain.fakes.entities - -import java.time.{LocalDate, LocalDateTime, LocalTime} - -import xyz.driver.core.generators._ -import xyz.driver.entities.common.FullName -import xyz.driver.entities.patient.CancerType -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue -import xyz.driver.pdsuicommon.domain.{LongId, StringId, TextJson, UuidId} -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ - -import scala.util.Random - -object common { - import xyz.driver.core.generators - - def nextUuidId[T]: UuidId[T] = UuidId[T](generators.nextUuid()) - - def nextLongId[T]: LongId[T] = LongId[T](generators.nextInt(Int.MaxValue).toLong) - - def nextStringId[T]: StringId[T] = StringId[T](generators.nextString(maxLength = 20)) - - def nextTrialStatus: Trial.Status = generators.oneOf[Trial.Status](Trial.Status.All) - - def nextPreviousTrialStatus: Trial.Status = generators.oneOf[Trial.Status](Trial.Status.AllPrevious) - - def nextLocalDateTime: LocalDateTime = LocalDateTime.of(nextLocalDate, LocalTime.MIDNIGHT) - - def nextLocalDate: LocalDate = LocalDate.of( - 1970 + Random.nextInt(68), - 1 + Random.nextInt(12), - 1 + Random.nextInt(28) // all months have at least 28 days - ) - - def nextTrialAction = generators.oneOf[TrialHistory.Action](TrialHistory.Action.All) - - def nextTrialState = generators.oneOf[TrialHistory.State](TrialHistory.State.All) - - def genBoundedRange[T](from: T, to: T)(implicit ord: Ordering[T]): (T, T) = { - if (ord.compare(from, to) > 0) { - to -> from - } else { - from -> to - } - } - - def genBoundedRangeOption[T](from: T, to: T)(implicit ord: Ordering[T]): (Option[T], Option[T]) = { - val ranges = nextOption(from).map { left => - val range = genBoundedRange(left, to) - range._1 -> nextOption(range._2) - } - - ranges.map(_._1) -> ranges.flatMap(_._2) - } - - def nextStartAndEndPagesOption: (Option[Double], Option[Double]) = - genBoundedRangeOption[Double](nextDouble(), nextDouble()) - - def nextStartAndEndPages: (Double, Double) = - genBoundedRange(nextDouble(), nextDouble()) - - def nextPatientStatus: Patient.Status = generators.oneOf[Patient.Status](Patient.Status.All) - - def nextFullName[T]: FullName[T] = FullName( - firstName = generators.nextName[T](10), - middleName = generators.nextName[T](10), - lastName = generators.nextName[T](10) - ) - - def nextCancerType: CancerType = - generators.oneOf[CancerType](CancerType.Breast, CancerType.Lung, CancerType.Prostate) - - private val maxAttemptsNumber = 100 - - def nextBridgeUploadQueueItem(): BridgeUploadQueue.Item = { - BridgeUploadQueue.Item( - kind = nextString(), - tag = nextString(), - created = nextLocalDateTime, - attempts = nextInt(maxAttemptsNumber, minValue = 0), - nextAttempt = nextLocalDateTime, - completed = nextBoolean(), - dependencyKind = nextOption(nextString()), - dependencyTag = nextOption(nextString()) - ) - } - - def nextBridgeUploadQueueItemListResponse(): ListResponse[BridgeUploadQueue.Item] = { - val xs: Seq[BridgeUploadQueue.Item] = Seq.fill(3)(nextBridgeUploadQueueItem()) - nextListResponse(xs) - } - - def nextDocumentType(): DocumentType = generators.oneOf[DocumentType](DocumentType.All: _*) - - def nextProviderType(): ProviderType = generators.oneOf[ProviderType](ProviderType.All: _*) - - def nextDocumentTypeListResponse(): ListResponse[DocumentType] = { - val xs: Seq[DocumentType] = Seq.fill(3)(nextDocumentType()) - nextListResponse(xs) - } - - def nextProviderTypeListResponse(): ListResponse[ProviderType] = { - val xs: Seq[ProviderType] = Seq.fill(3)(nextProviderType()) - nextListResponse(xs) - } - - def nextTextJson[T](obj: T): TextJson[T] = TextJson(obj) - - def nextListResponse[T](xs: Seq[T]): ListResponse[T] = { - val pageSize = generators.nextInt(xs.size, 1) - ListResponse( - items = xs, - meta = ListResponse.Meta( - itemsCount = xs.size, - pageNumber = generators.nextInt(xs.size / pageSize), - pageSize = pageSize, - lastUpdate = generators.nextOption(nextLocalDateTime) - ) - ) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/eligibility.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/eligibility.scala deleted file mode 100644 index 1796fe6..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/eligibility.scala +++ /dev/null @@ -1,72 +0,0 @@ -package xyz.driver.pdsuidomain.fakes.entities - -import xyz.driver.core.generators -import xyz.driver.entities.clinic.{ClinicalRecord, TestOrder} -import xyz.driver.entities.patient.{CancerType, Patient} -import xyz.driver.entities.report.Report -import xyz.driver.fakes -import xyz.driver.pdsuidomain.entities.eligibility._ - -object eligibility { - import xyz.driver.core.generators._ - - def nextMolecularEvidenceDocument(): MolecularEvidenceDocument = - MolecularEvidenceDocument( - documentType = xyz.driver.pdsuidomain.fakes.entities.common.nextDocumentType(), - providerType = xyz.driver.pdsuidomain.fakes.entities.common.nextProviderType(), - providerName = nextOption(nextString(100)), - date = nextOption(nextDate()), - reportId = nextId[Report](), - reportType = fakes.entities.assays.nextAssayType(), - isDriverDocument = nextBoolean() - ) - - def nextClinicalEvidenceDocument(): ClinicalEvidenceDocument = - ClinicalEvidenceDocument( - documentType = xyz.driver.pdsuidomain.fakes.entities.common.nextDocumentType(), - providerType = xyz.driver.pdsuidomain.fakes.entities.common.nextProviderType(), - providerName = nextOption(nextString(100)), - date = nextOption(nextDate()), - documentId = nextId[ClinicalEvidenceDocument](), - requestId = nextId[ClinicalRecord](), - isDriverDocument = nextBoolean() - ) - - def nextEvidenceDocument(): EvidenceDocument = - oneOf[EvidenceDocument](nextMolecularEvidenceDocument(), - nextClinicalEvidenceDocument(), - nextClinicalEvidenceDocument()) // For more clinical documents - - def nextEvidence(): Evidence = - Evidence( - evidenceId = Option(nextId[Evidence]()), - evidenceText = nextString(100), - labelValue = xyz.driver.fakes.entities.labels.nextLabelValue(), - nextEvidenceDocument(), - isPrimaryValue = nextOption(nextBoolean()) - ) - - def nextLabelEvidence(): LabelEvidence = - LabelEvidence(label = fakes.entities.labels.nextLabel(), evidence = Seq.empty) - - def nextLabelMismatchRank(): LabelMismatchRank = - LabelMismatchRank( - label = fakes.entities.labels.nextLabel(), - score = nextInt(100), - trials = seqOf(xyz.driver.pdsuidomain.fakes.entities.export.nextExportTrialWithLabels()), - evidence = seqOf(nextEvidence()) - ) - - def nextMismatchRankedLabels(): MismatchRankedLabels = - MismatchRankedLabels(data = seqOf(nextLabelMismatchRank()), labelVersion = nextInt(100)) - - def nextMatchedPatient(): MatchedPatient = - MatchedPatient( - patientId = nextId[Patient](), - name = fakes.entities.common.nextFullName[Patient](), - birthDate = nextDate(), - orderId = nextId[TestOrder](), - disease = generators.oneOf[CancerType](CancerType.Breast, CancerType.Lung, CancerType.Prostate), - patientDataStatus = fakes.entities.process.nextProcessStepExecutionStatus() - ) -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala deleted file mode 100644 index 12eff61..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala +++ /dev/null @@ -1,76 +0,0 @@ -package xyz.driver.pdsuidomain.fakes.entities - -import xyz.driver.core.generators -import xyz.driver.entities.clinic.ClinicalRecord -import xyz.driver.entities.labels.Label -import xyz.driver.fakes -import xyz.driver.pdsuidomain.entities.export.patient._ -import xyz.driver.pdsuidomain.entities.export.trial._ -import xyz.driver.pdsuidomain.entities._ - -object export { - import common._ - import xyz.driver.core.generators._ - - def nextExportTrialArm(): ExportTrialArm = - ExportTrialArm(armId = nextLongId[EligibilityArm], - armName = nextString(100), - diseaseList = listOf(nextString(100))) - - def nextExportTrialLabelCriterion(): ExportTrialLabelCriterion = - ExportTrialLabelCriterion( - criterionId = nextLongId[Criterion], - value = nextOption[Boolean](nextBoolean()), - labelId = nextLongId[Label], - armIds = setOf(nextLongId[EligibilityArm]), - criteria = nextString(100), - isCompound = nextBoolean(), - isDefining = nextBoolean(), - inclusion = nextOption(nextBoolean()) - ) - - def nextExportTrialWithLabels(): ExportTrialWithLabels = - ExportTrialWithLabels( - nctId = nextStringId[Trial], - trialId = nextUuidId[Trial], - lastReviewed = nextLocalDateTime, - labelVersion = nextInt(100).toLong, - arms = listOf(nextExportTrialArm()), - criteria = listOf(nextExportTrialLabelCriterion()) - ) - - def nextExportPatientLabelEvidenceDocument(): ExportPatientLabelEvidenceDocument = { - ExportPatientLabelEvidenceDocument( - documentId = nextLongId[Document], - requestId = generators.nextId[ClinicalRecord](), - documentType = nextDocumentType(), - providerType = nextProviderType(), - date = nextLocalDate - ) - } - - def nextExportPatientLabelEvidence(): ExportPatientLabelEvidence = { - ExportPatientLabelEvidence( - id = nextLongId[ExtractedData], - value = fakes.entities.labels.nextLabelValue(), - evidenceText = nextString(), - document = nextExportPatientLabelEvidenceDocument() - ) - } - - def nextExportPatientLabel(): ExportPatientLabel = { - ExportPatientLabel( - id = nextLongId[Label], - evidences = List.fill(nextInt(10))(nextExportPatientLabelEvidence()) - ) - } - - def nextExportPatientWithLabels(): ExportPatientWithLabels = { - ExportPatientWithLabels( - patientId = nextUuidId[Patient], - labelVersion = nextInt(Int.MaxValue).toLong, - labels = List.fill(nextInt(10))(nextExportPatientLabel()) - ) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/recordprocessing.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/recordprocessing.scala deleted file mode 100644 index d3d76b8..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/recordprocessing.scala +++ /dev/null @@ -1,322 +0,0 @@ -package xyz.driver.pdsuidomain.fakes.entities - -import java.time.LocalDate - -import xyz.driver.core.auth.User -import xyz.driver.core.generators -import xyz.driver.core.generators._ -import xyz.driver.entities.assays.PatientCase -import xyz.driver.entities.clinic.ClinicalRecord -import xyz.driver.entities.labels.{Label, LabelCategory, LabelValue} -import xyz.driver.pdsuicommon.domain.{LongId, TextJson} -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities.ExtractedData.Meta -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.fakes.entities.common._ -import xyz.driver.pdsuidomain.services.ExtractedDataService.RichExtractedData - -object recordprocessing { - - private val maxItemsInCollectionNumber: Int = 50 - private val maxPageNumber = 100 - private val maxIndexNumber = 100 - private val maxOffsetNumber = 10 - - implicit private class LocalDateOrdering(localData: LocalDate) extends Ordered[LocalDate] { - override def compare(that: LocalDate): Int = { - this.localData.compareTo(that) - } - } - - implicit private class TextLayerPositionOrdering(textLayerPosition: ExtractedData.Meta.TextLayerPosition) - extends Ordered[ExtractedData.Meta.TextLayerPosition] { - override def compare(that: Meta.TextLayerPosition): Int = { - if (this.textLayerPosition.page < that.page) -1 - else if (this.textLayerPosition.page > that.page) 1 - else if (this.textLayerPosition.index < that.index) -1 - else if (this.textLayerPosition.index > that.index) 1 - else if (this.textLayerPosition.offset < that.offset) -1 - else if (this.textLayerPosition.offset > that.offset) 1 - else 0 - } - } - - private def nextDates(): (Option[LocalDate], Option[LocalDate]) = - genBoundedRangeOption[LocalDate](nextLocalDate, nextLocalDate) - - private val medicalRecordMeta: Set[() => MedicalRecord.Meta] = { - Set( - () => nextMedicalRecordMetaReorder(), - () => nextMedicalRecordMetaDuplicate(), - () => nextMedicalRecordMetaRotation() - ) - } - - def nextMedicalRecordMeta(count: Int): List[MedicalRecord.Meta] = - List.fill(count)(nextMedicalRecordMeta()) - - def nextMedicalRecordMetaJson(): TextJson[List[MedicalRecord.Meta]] = - TextJson(nextMedicalRecordMeta(nextInt(maxItemsInCollectionNumber))) - - private def nextDocumentList(count: Int): List[Document] = - List.fill(count)(nextDocument()) - - def nextDocumentList(recordId: LongId[MedicalRecord]): TextJson[List[Document]] = { - val documents = nextDocumentList( - nextInt(maxItemsInCollectionNumber) - ) - TextJson(documents.map(_.copy(recordId = recordId))) - } - - def nextMedicalRecordStatus(): MedicalRecord.Status = - generators.oneOf[MedicalRecord.Status](MedicalRecord.Status.All) - - def nextMedicalRecordHistoryState(): MedicalRecordHistory.State = - generators.oneOf[MedicalRecordHistory.State](MedicalRecordHistory.State.All) - - def nextMedicalRecordHistoryAction(): MedicalRecordHistory.Action = - generators.oneOf[MedicalRecordHistory.Action](MedicalRecordHistory.Action.All) - - def nextMedicalRecordMetaReorder(): MedicalRecord.Meta.Reorder = { - val itemsNumber = maxItemsInCollectionNumber - val items = scala.util.Random.shuffle(Seq.tabulate(itemsNumber)(identity)) - - MedicalRecord.Meta.Reorder(items) - } - - def nextMedicalRecordMetaDuplicate(): MedicalRecord.Meta.Duplicate = { - val startPageGen = nextInt(maxPageNumber) - val endPageGen = nextInt(maxPageNumber, startPageGen) - - MedicalRecord.Meta.Duplicate( - startPage = startPageGen.toDouble, - endPage = endPageGen.toDouble, - startOriginalPage = startPageGen.toDouble, - endOriginalPage = nextOption(endPageGen.toDouble) - ) - } - - def nextMedicalRecordMetaRotation(): MedicalRecord.Meta.Rotation = { - val items = Array.tabulate(maxItemsInCollectionNumber)(index => nextString() -> index).toMap - - MedicalRecord.Meta.Rotation(items = items) - } - - def nextMedicalRecordMeta(): MedicalRecord.Meta = generators.oneOf(medicalRecordMeta)() - - def nextMedicalRecord(): MedicalRecord = MedicalRecord( - id = nextLongId[MedicalRecord], - status = nextMedicalRecordStatus(), - previousStatus = nextOption(generators.oneOf[MedicalRecord.Status](MedicalRecord.Status.AllPrevious)), - assignee = nextOption(generators.nextId[User]), - previousAssignee = nextOption(generators.nextId[User]), - lastActiveUserId = nextOption(generators.nextId[User]), - patientId = nextUuidId[Patient], - requestId = generators.nextId[ClinicalRecord](), - disease = generators.nextString(), - caseId = nextOption(generators.nextId[PatientCase]()), - physician = nextOption(generators.nextString()), - meta = nextOption(nextMedicalRecordMetaJson()), - lastUpdate = nextLocalDateTime, - totalPages = nextInt(10) - ) - - def nextMedicalRecordHistory(): MedicalRecordHistory = MedicalRecordHistory( - id = nextLongId[MedicalRecordHistory], - executor = generators.nextId[User], - recordId = nextLongId[MedicalRecord], - state = nextMedicalRecordHistoryState(), - action = nextMedicalRecordHistoryAction(), - created = nextLocalDateTime - ) - - def nextMedicalRecordIssue(): MedicalRecordIssue = { - val (startPage, endPage) = nextStartAndEndPagesOption - - MedicalRecordIssue( - id = nextLongId[MedicalRecordIssue], - userId = generators.nextId[User], - recordId = nextLongId[MedicalRecord], - startPage = startPage, - endPage = endPage, - lastUpdate = nextLocalDateTime, - isDraft = nextBoolean(), - text = nextString(), - archiveRequired = nextBoolean() - ) - } - - def nextDocumentStatus(): Document.Status = generators.oneOf[Document.Status](Document.Status.All) - - def nextDocumentRequiredType(): Document.RequiredType = - generators.oneOf[Document.RequiredType](Document.RequiredType.All) - - def nextDocumentHistoryState(): DocumentHistory.State = - generators.oneOf[DocumentHistory.State](DocumentHistory.State.All) - - def nextDocumentHistoryAction(): DocumentHistory.Action = - generators.oneOf[DocumentHistory.Action](DocumentHistory.Action.All) - - def nextDocumentMeta(): Document.Meta = { - val (startPage, endPage) = nextStartAndEndPages - Document.Meta(startPage, endPage) - } - - def nextDocumentMetaJson(): TextJson[Document.Meta] = nextTextJson(nextDocumentMeta()) - - def nextDocument(): Document = { - val (startDate, endDate) = nextDates() - - Document( - id = nextLongId[Document], - status = nextDocumentStatus(), - previousStatus = nextOption(generators.oneOf[Document.Status](Document.Status.AllPrevious)), - assignee = nextOption(generators.nextId[User]), - previousAssignee = nextOption(generators.nextId[User]), - lastActiveUserId = nextOption(generators.nextId[User]), - recordId = nextLongId[MedicalRecord], - physician = nextOption(nextString()), - typeId = nextOption(nextLongId[DocumentType]), - providerName = nextOption(nextString()), - providerTypeId = nextOption(nextLongId[ProviderType]), - requiredType = nextOption(nextDocumentRequiredType()), - institutionName = nextOption(nextString()), - meta = nextOption(nextDocumentMetaJson()), - startDate = startDate, - endDate = endDate, - lastUpdate = nextLocalDateTime, - labelVersion = generators.nextInt(100) - ) - } - - def nextDocumentIssue(): DocumentIssue = { - val (startPage, endPage) = nextStartAndEndPagesOption - DocumentIssue( - id = nextLongId[DocumentIssue], - userId = generators.nextId[User], - documentId = nextLongId[Document], - startPage = startPage, - endPage = endPage, - lastUpdate = nextLocalDateTime, - isDraft = nextBoolean(), - text = nextString(), - archiveRequired = nextBoolean() - ) - } - - def nextDocumentHistory(): DocumentHistory = DocumentHistory( - id = nextLongId[DocumentHistory], - executor = generators.nextId[User], - documentId = nextLongId[Document], - state = nextDocumentHistoryState(), - action = nextDocumentHistoryAction(), - created = nextLocalDateTime - ) - - def nextExtractedDataMetaKeyword(): Meta.Keyword = { - ExtractedData.Meta.Keyword( - page = nextInt(maxPageNumber), - pageRatio = nextOption(nextDouble()), - index = nextInt(maxIndexNumber), - sortIndex = nextString() - ) - } - - def nextExtractedDataMetaTextLayerPosition(): Meta.TextLayerPosition = { - ExtractedData.Meta.TextLayerPosition( - page = nextInt(maxPageNumber), - index = nextInt(maxIndexNumber), - offset = nextInt(maxOffsetNumber) - ) - } - - def nextExtractedDataMetaEvidence(): Meta.Evidence = { - val (start, end) = - genBoundedRange[ExtractedData.Meta.TextLayerPosition]( - nextExtractedDataMetaTextLayerPosition(), - nextExtractedDataMetaTextLayerPosition() - ) - - ExtractedData.Meta.Evidence( - pageRatio = nextDouble(), - start = start, - end = end - ) - } - - def nextExtractedDataMeta(): Meta = { - ExtractedData.Meta( - nextOption(nextExtractedDataMetaKeyword()), - nextOption(nextExtractedDataMetaEvidence()) - ) - } - - def nextExtractedDataMetaJson(): TextJson[Meta] = - nextTextJson(nextExtractedDataMeta()) - - def nextExtractedData(): ExtractedData = { - ExtractedData( - id = nextLongId[ExtractedData], - documentId = nextLongId[Document], - keywordId = nextOption(nextLongId[Keyword]), - evidenceText = nextOption(nextString()), - meta = nextOption(nextExtractedDataMetaJson()) - ) - } - - def nextExtractedDataLabel(): ExtractedDataLabel = { - ExtractedDataLabel( - id = nextLongId[ExtractedDataLabel], - dataId = nextLongId[ExtractedData], - labelId = nextOption(nextLongId[Label]), - categoryId = nextOption(nextLongId[LabelCategory]), - value = nextOption(generators.oneOf[LabelValue](LabelValue.Yes, LabelValue.No, LabelValue.Maybe)) - ) - } - - def nextRichExtractedData(): RichExtractedData = { - val extractedData = nextExtractedData() - RichExtractedData( - extractedData = extractedData, - labels = List.fill( - nextInt(maxItemsInCollectionNumber) - )(nextExtractedDataLabel()) - ) - } - - def nextMedicalRecordListResponse(): ListResponse[MedicalRecord] = { - val xs: Seq[MedicalRecord] = Seq.fill(3)(nextMedicalRecord()) - nextListResponse(xs) - } - - def nextMedicalRecordIssueListResponse(): ListResponse[MedicalRecordIssue] = { - val xs: Seq[MedicalRecordIssue] = Seq.fill(3)(nextMedicalRecordIssue()) - nextListResponse(xs) - } - - def nextMedicalRecordHistoryListResponse(): ListResponse[MedicalRecordHistory] = { - val xs: Seq[MedicalRecordHistory] = Seq.fill(3)(nextMedicalRecordHistory()) - nextListResponse(xs) - } - - def nextDocumentListResponse(): ListResponse[Document] = { - val xs: Seq[Document] = Seq.fill(3)(nextDocument()) - nextListResponse(xs) - } - - def nextDocumentIssueListResponse(): ListResponse[DocumentIssue] = { - val xs: Seq[DocumentIssue] = Seq.fill(3)(nextDocumentIssue()) - nextListResponse(xs) - } - - def nextDocumentHistoryListResponse(): ListResponse[DocumentHistory] = { - val xs: Seq[DocumentHistory] = Seq.fill(3)(nextDocumentHistory()) - nextListResponse(xs) - } - - def nextRichExtractedDataListResponse(): ListResponse[RichExtractedData] = { - val xs: Seq[RichExtractedData] = Seq.fill(3)(nextRichExtractedData()) - nextListResponse(xs) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/rep/DocumentGen.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/rep/DocumentGen.scala deleted file mode 100644 index 8b13789..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/rep/DocumentGen.scala +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/treatmentmatching.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/treatmentmatching.scala deleted file mode 100644 index 190add6..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/treatmentmatching.scala +++ /dev/null @@ -1,233 +0,0 @@ -package xyz.driver.pdsuidomain.fakes.entities - -import eu.timepit.refined.numeric.NonNegative -import xyz.driver.entities.labels.Label -import xyz.driver.fakes -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ -import eu.timepit.refined.{refineMV, refineV} -import xyz.driver.core.auth.User - -object treatmentmatching { - import common._ - import xyz.driver.core.generators - - final case class DraftPatientCriterionList(list: List[DraftPatientCriterion]) - object DraftPatientCriterionList { - import spray.json._ - import xyz.driver.pdsuidomain.formats.json.patientcriterion._ - - implicit val draftPatientCriterionListFormat: RootJsonFormat[DraftPatientCriterionList] = - new RootJsonFormat[DraftPatientCriterionList] { - override def write(obj: DraftPatientCriterionList): JsValue = { - JsArray(obj.list.map(_.toJson).toVector) - } - - override def read(json: JsValue): DraftPatientCriterionList = json match { - case j: JsObject => - DraftPatientCriterionList(draftPatientCriterionListReader.read(j)) - - case _ => deserializationError(s"Expected List of DraftPatientCriterion json object, but got $json") - } - } - } - - def nextPatientAction: PatientHistory.Action = - generators.oneOf[PatientHistory.Action](PatientHistory.Action.All) - - def nextPatientState: PatientHistory.State = - generators.oneOf[PatientHistory.State](PatientHistory.State.All) - - def nextPatient(): Patient = Patient( - id = nextUuidId[Patient], - status = nextPatientStatus, - name = nextFullName[Patient], - dob = nextLocalDate, - assignee = generators.nextOption(generators.nextId[User]), - previousStatus = generators.nextOption(generators.oneOf[Patient.Status](Patient.Status.AllPrevious)), - previousAssignee = generators.nextOption(generators.nextId[User]), - lastActiveUserId = generators.nextOption(generators.nextId[User]), - isUpdateRequired = generators.nextBoolean(), - disease = nextCancerType, - orderId = generators.nextId(), - lastUpdate = nextLocalDateTime - ) - - def nextPatientLabel(): PatientLabel = PatientLabel( - id = nextLongId[PatientLabel], - patientId = nextUuidId[Patient], - labelId = nextLongId[Label], - score = generators.nextInt(100), - primaryValue = fakes.entities.labels.nextLabelValue(), - verifiedPrimaryValue = fakes.entities.labels.nextLabelValue(), - isImplicitMatch = generators.nextBoolean(), - isVisible = generators.nextBoolean() - ) - - def nextRichPatientLabel(): RichPatientLabel = RichPatientLabel( - patientLabel = nextPatientLabel(), - isVerified = generators.nextBoolean() - ) - - def nextPatientCriterion(): PatientCriterion = PatientCriterion( - id = nextLongId[PatientCriterion], - patientLabelId = nextLongId[PatientLabel], - trialId = generators.nextInt(Int.MaxValue).toLong, - nctId = nextStringId[Trial], - criterionId = nextLongId[Criterion], - criterionText = generators.nextString(), - criterionValue = generators.nextOption(generators.nextBoolean()), - criterionIsDefining = generators.nextBoolean(), - eligibilityStatus = fakes.entities.labels.nextLabelValue(), - verifiedEligibilityStatus = fakes.entities.labels.nextLabelValue(), - isVerified = generators.nextBoolean(), - isVisible = generators.nextBoolean(), - lastUpdate = nextLocalDateTime, - inclusion = generators.nextOption(generators.nextBoolean()) - ) - - def nextDraftPatientCriterion(): DraftPatientCriterion = DraftPatientCriterion( - id = nextLongId[PatientCriterion], - eligibilityStatus = generators.nextOption(fakes.entities.labels.nextLabelValue()), - isVerified = generators.nextOption(generators.nextBoolean()) - ) - - def nextDraftPatientCriterionList(): DraftPatientCriterionList = { - DraftPatientCriterionList(List.fill(3)(nextDraftPatientCriterion())) - } - - def nextPatientCriterionArm(criterionId: LongId[PatientCriterion]): PatientCriterionArm = PatientCriterionArm( - patientCriterionId = criterionId, - armId = nextLongId[Arm], - armName = generators.nextString() - ) - - def nextRichPatientCriterion(): RichPatientCriterion = { - val patientCriterion = nextPatientCriterion() - RichPatientCriterion( - patientCriterion = patientCriterion, - labelId = nextLongId[Label], - armList = List( - nextPatientCriterionArm(patientCriterion.id), - nextPatientCriterionArm(patientCriterion.id), - nextPatientCriterionArm(patientCriterion.id) - ) - ) - } - - def nextPatientLabelEvidenceView(): PatientLabelEvidenceView = PatientLabelEvidenceView( - id = nextLongId[PatientLabelEvidence], - value = fakes.entities.labels.nextLabelValue(), - evidenceText = generators.nextString(), - documentId = generators.nextOption(nextLongId[Document]), - evidenceId = generators.nextOption(nextLongId[ExtractedData]), - reportId = generators.nextOption(nextUuidId[DirectReport]), - documentType = nextDocumentType(), - date = generators.nextOption(nextLocalDate), - providerType = nextProviderType(), - patientId = nextUuidId[Patient], - labelId = nextLongId[Label], - isImplicitMatch = generators.nextBoolean() - ) - - def nextPatientTrialArmGroupView(trialId: StringId[Trial]): PatientTrialArmGroupView = PatientTrialArmGroupView( - id = nextLongId[PatientTrialArmGroup], - patientId = nextUuidId[Patient], - trialId = trialId, - hypothesisId = nextUuidId[Hypothesis], - eligibilityStatus = fakes.entities.labels.nextLabelValue(), - verifiedEligibilityStatus = fakes.entities.labels.nextLabelValue(), - isVerified = generators.nextBoolean() - ) - - def nextRichPatientEligibleTrial(): RichPatientEligibleTrial = { - val patientCriterionId = nextLongId[PatientCriterion] - val trial = trialcuration.nextTrial() - RichPatientEligibleTrial( - trial = trial, - group = nextPatientTrialArmGroupView(trial.id), - arms = List( - nextPatientCriterionArm(patientCriterionId), - nextPatientCriterionArm(patientCriterionId), - nextPatientCriterionArm(patientCriterionId) - ) - ) - } - - def nextPatientHypothesis(): PatientHypothesis = PatientHypothesis( - id = nextUuidId[PatientHypothesis], - patientId = nextUuidId[Patient], - hypothesisId = nextUuidId[Hypothesis], - rationale = Option(generators.nextString()), - matchedTrials = refineV[NonNegative](generators.nextInt(Int.MaxValue).toLong) match { - case Left(_) => refineMV[NonNegative](0) - case Right(nonNegative) => nonNegative - } - ) - - def nextPatientIssue(): PatientIssue = PatientIssue( - id = nextLongId[PatientIssue], - userId = generators.nextId[User], - patientId = nextUuidId[Patient], - lastUpdate = nextLocalDateTime, - isDraft = generators.nextBoolean(), - text = generators.nextString(), - archiveRequired = generators.nextBoolean() - ) - - def nextPatientHistory(): PatientHistory = PatientHistory( - id = nextLongId[PatientHistory], - executor = generators.nextId[User], - patientId = nextUuidId[Patient], - state = nextPatientState, - action = nextPatientAction, - created = nextLocalDateTime - ) - - def nextPatientListResponse(): ListResponse[Patient] = { - val xs: Seq[Patient] = Seq.fill(3)(nextPatient()) - nextListResponse(xs) - } - - def nextRichPatientLabelListResponse(): ListResponse[RichPatientLabel] = { - val xs: Seq[RichPatientLabel] = Seq.fill(3)(nextRichPatientLabel()) - nextListResponse(xs) - } - - def nextPatientLabelListResponse(): ListResponse[PatientLabel] = { - val xs: Seq[PatientLabel] = Seq.fill(3)(nextPatientLabel()) - nextListResponse(xs) - } - - def nextRichPatientCriterionListResponse(): ListResponse[RichPatientCriterion] = { - val xs: Seq[RichPatientCriterion] = Seq.fill(3)(nextRichPatientCriterion()) - nextListResponse(xs) - } - - def nextRichPatientEligibleTrialListResponse(): ListResponse[RichPatientEligibleTrial] = { - val xs: Seq[RichPatientEligibleTrial] = Seq.fill(3)(nextRichPatientEligibleTrial()) - nextListResponse(xs) - } - - def nextPatientHypothesisListResponse(): ListResponse[PatientHypothesis] = { - val xs: Seq[PatientHypothesis] = Seq.fill(3)(nextPatientHypothesis()) - nextListResponse(xs) - } - - def nextPatientLabelEvidenceViewListResponse(): ListResponse[PatientLabelEvidenceView] = { - val xs: Seq[PatientLabelEvidenceView] = Seq.fill(3)(nextPatientLabelEvidenceView()) - nextListResponse(xs) - } - - def nextPatientIssuesListResponse(): ListResponse[PatientIssue] = { - val xs: Seq[PatientIssue] = Seq.fill(3)(nextPatientIssue()) - nextListResponse(xs) - } - - def nextPatientHistoryListResponse(): ListResponse[PatientHistory] = { - val xs: Seq[PatientHistory] = Seq.fill(3)(nextPatientHistory()) - nextListResponse(xs) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/trialcuration.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/trialcuration.scala deleted file mode 100644 index 925a019..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/trialcuration.scala +++ /dev/null @@ -1,239 +0,0 @@ -package xyz.driver.pdsuidomain.fakes.entities - -import xyz.driver.core.auth.User -import xyz.driver.core.generators._ -import xyz.driver.entities.labels.{Label, LabelCategory} -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.CriterionService.RichCriterion - -object trialcuration { - - import common._ - import xyz.driver.core.generators - import xyz.driver.pdsuidomain.entities.InterventionType._ - - private val maxItemsInCollectionNumber: Int = 5 - - def nextTrial(): Trial = Trial( - id = nextStringId[Trial], - externalId = nextUuidId[Trial], - status = nextTrialStatus, - assignee = Option(generators.nextId[User]), - previousStatus = Option(nextPreviousTrialStatus), - previousAssignee = Option(generators.nextId[User]), - lastActiveUserId = Option(generators.nextId[User]), - lastUpdate = nextLocalDateTime, - phase = generators.nextString(), - hypothesisId = Option(nextUuidId[Hypothesis]), - studyDesignId = Option(nextLongId[StudyDesign]), - originalStudyDesign = Option(generators.nextString()), - isPartner = generators.nextBoolean(), - overview = Option(generators.nextString()), - overviewTemplate = generators.nextString(), - isUpdated = generators.nextBoolean(), - title = generators.nextString(), - originalTitle = generators.nextString() - ) - - def nextArm(): Arm = Arm( - id = nextLongId[Arm], - name = generators.nextString(), - originalName = generators.nextString(), - trialId = nextStringId[Trial], - deleted = Option(nextLocalDateTime) - ) - - def nextCriterion(): Criterion = Criterion( - id = nextLongId[Criterion], - trialId = nextStringId[Trial], - text = Option(generators.nextString()), - isCompound = generators.nextBoolean(), - meta = generators.nextString(), - inclusion = Option(generators.nextBoolean()) - ) - - def nextCriterionLabel(criterionId: LongId[Criterion]): CriterionLabel = CriterionLabel( - id = nextLongId[CriterionLabel], - labelId = Option(nextLongId[Label]), - criterionId = criterionId, - categoryId = Option(nextLongId[LabelCategory]), - value = Option(generators.nextBoolean()), - isDefining = generators.nextBoolean() - ) - - def nextRichCriterion(): RichCriterion = { - val criterion = nextCriterion() - RichCriterion( - criterion = criterion, - armIds = Seq(nextLongId[EligibilityArm], nextLongId[EligibilityArm]), - labels = Seq( - nextCriterionLabel(criterion.id), - nextCriterionLabel(criterion.id) - ) - ) - } - - def nextIntervention(): Intervention = Intervention( - id = nextLongId[Intervention], - trialId = nextStringId[Trial], - name = generators.nextString(), - originalName = generators.nextString(), - typeId = Option(nextLongId[InterventionType]), - originalType = Option(generators.nextString()), - dosage = generators.nextString(), - originalDosage = generators.nextString(), - isActive = generators.nextBoolean(), - deliveryMethod = Option(generators.nextString()) - ) - - def nextInterventionArm(interventionId: LongId[Intervention]): InterventionArm = InterventionArm( - interventionId = interventionId, - armId = nextLongId[SlotArm] - ) - - def nextInterventionWithArms(): InterventionWithArms = { - val intervention = nextIntervention() - InterventionWithArms( - intervention = intervention, - arms = List( - nextInterventionArm(intervention.id), - nextInterventionArm(intervention.id), - nextInterventionArm(intervention.id) - ) - ) - } - - def nextTrialIssue(): TrialIssue = TrialIssue( - id = nextLongId[TrialIssue], - userId = generators.nextId[User], - trialId = nextStringId[Trial], - lastUpdate = nextLocalDateTime, - isDraft = generators.nextBoolean(), - text = generators.nextString(), - evidence = generators.nextString(), - archiveRequired = generators.nextBoolean(), - meta = generators.nextString() - ) - - def nextTrialHistory(): TrialHistory = TrialHistory( - id = nextLongId[TrialHistory], - executor = generators.nextId[User], - trialId = nextStringId[Trial], - state = nextTrialState, - action = nextTrialAction, - created = nextLocalDateTime, - comment = generators.nextOption(generators.nextString()) - ) - - def nextHypothesis(): Hypothesis = Hypothesis( - id = nextUuidId[Hypothesis], - name = generators.nextString(), - treatmentType = generators.nextString(), - description = generators.nextString() - ) - - def nextStudyDesign(): StudyDesign = generators.oneOf[StudyDesign](StudyDesign.All: _*) - - def nextInterventionType(): InterventionType = generators.oneOf[InterventionType]( - Chemotherapy, - TargetedTherapy, - Immunotherapy, - HormoneTherapy, - Other, - Radiation, - SurgeryProcedure - ) - - def nextEligibilityArm(): EligibilityArm = EligibilityArm( - id = nextLongId, - name = nextString(), - originalName = nextString(), - trialId = nextStringId - ) - - def nextEligibilityArmDisease(): EligibilityArmDisease = EligibilityArmDisease( - eligibilityArmId = nextLongId, - disease = nextCancerType - ) - - private def nextEligibilityArmDiseaseCollection(count: Int): Seq[EligibilityArmDisease] = - Seq.fill(count)(nextEligibilityArmDisease()) - - def nextEligibilityArmWithDiseases(): EligibilityArmWithDiseases = { - val entity = nextEligibilityArm() - val id = entity.id - val collection = nextEligibilityArmDiseaseCollection( - nextInt(maxItemsInCollectionNumber, minValue = 0) - ).map(_.copy(eligibilityArmId = id)) - - EligibilityArmWithDiseases( - entity, - collection - ) - } - - def nextSlotArm(): SlotArm = SlotArm( - id = nextLongId, - name = nextString(), - originalName = nextString(), - trialId = nextStringId - ) - - def nextTrialListResponse(): ListResponse[Trial] = { - val xs: Seq[Trial] = Seq.fill(3)(nextTrial()) - nextListResponse(xs) - } - - def nextTrialIssueListResponse(): ListResponse[TrialIssue] = { - val xs: Seq[TrialIssue] = Seq.fill(3)(nextTrialIssue()) - nextListResponse(xs) - } - - def nextTrialHistoryListResponse(): ListResponse[TrialHistory] = { - val xs: Seq[TrialHistory] = Seq.fill(3)(nextTrialHistory()) - nextListResponse(xs) - } - - def nextArmListResponse(): ListResponse[Arm] = { - val xs: Seq[Arm] = Seq.fill(3)(nextArm()) - nextListResponse(xs) - } - - def nextInterventionWithArmsListResponse(): ListResponse[InterventionWithArms] = { - val xs: Seq[InterventionWithArms] = Seq.fill(3)(nextInterventionWithArms()) - nextListResponse(xs) - } - - def nextEligibilityArmWithDiseasesListResponse(): ListResponse[EligibilityArmWithDiseases] = { - val xs: Seq[EligibilityArmWithDiseases] = Seq.fill(3)(nextEligibilityArmWithDiseases()) - nextListResponse(xs) - } - - def nextSlotArmListResponse(): ListResponse[SlotArm] = { - val xs: Seq[SlotArm] = Seq.fill(3)(nextSlotArm()) - nextListResponse(xs) - } - - def nextRichCriterionListResponse(): ListResponse[RichCriterion] = { - val xs: Seq[RichCriterion] = Seq.fill(3)(nextRichCriterion()) - nextListResponse(xs) - } - - def nextInterventionTypeListResponse(): ListResponse[InterventionType] = { - val xs: Seq[InterventionType] = Seq.fill(3)(nextInterventionType()) - nextListResponse(xs) - } - - def nextStudyDesignListResponse(): ListResponse[StudyDesign] = { - val xs: Seq[StudyDesign] = Seq.fill(3)(nextStudyDesign()) - nextListResponse(xs) - } - - def nextHypothesesListResponse(): ListResponse[Hypothesis] = { - val xs: Seq[Hypothesis] = Seq.fill(3)(nextHypothesis()) - nextListResponse(xs) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/arm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/arm.scala deleted file mode 100644 index 69029b6..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/arm.scala +++ /dev/null @@ -1,44 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities._ - -object arm { - import DefaultJsonProtocol._ - import common._ - - def applyUpdateToArm(json: JsValue, orig: Arm): Arm = json match { - case JsObject(fields) => - val name = fields - .get("name") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"Arm json object does not contain `name` field: $json")) - orig.copy(name = name) - - case _ => deserializationError(s"Expected Json Object as partial Arm, but got $json") - } - - implicit val armFormat: RootJsonFormat[Arm] = new RootJsonFormat[Arm] { - override def write(obj: Arm): JsValue = - JsObject( - "id" -> obj.id.toJson, - "name" -> obj.name.toJson, - "originalName" -> obj.originalName.toJson, - "trialId" -> obj.trialId.toJson - ) - - override def read(json: JsValue): Arm = json.asJsObject.getFields("trialId", "name") match { - case Seq(trialId, name) => - Arm( - id = json.asJsObject.fields.get("id").flatMap(_.convertTo[Option[LongId[Arm]]]).getOrElse(LongId(0)), - name = name.convertTo[String], - trialId = trialId.convertTo[StringId[Trial]], - originalName = name.convertTo[String] - ) - - case _ => deserializationError(s"Expected Json Object as Arm, but got $json") - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/bridgeuploadqueue.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/bridgeuploadqueue.scala deleted file mode 100644 index 6725a15..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/bridgeuploadqueue.scala +++ /dev/null @@ -1,68 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item - -object bridgeuploadqueue { - import DefaultJsonProtocol._ - import common._ - - implicit val queueUploadItemFormat: RootJsonFormat[BridgeUploadQueue.Item] = new RootJsonFormat[Item] { - override def write(obj: Item) = - JsObject( - "kind" -> obj.kind.toJson, - "tag" -> obj.tag.toJson, - "created" -> obj.created.toJson, - "attempts" -> obj.attempts.toJson, - "nextAttempt" -> obj.nextAttempt.toJson, - "completed" -> obj.completed.toJson - ) - - override def read(json: JsValue): Item = json match { - case JsObject(fields) => - val kind = fields - .get("kind") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"BridgeUploadQueue.Item json object does not contain `kind` field: $json")) - - val tag = fields - .get("tag") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"BridgeUploadQueue.Item json object does not contain `tag` field: $json")) - - val created = fields - .get("created") - .map(_.convertTo[LocalDateTime]) - .getOrElse( - deserializationError(s"BridgeUploadQueue.Item json object does not contain `created` field: $json")) - - val attempts = fields - .get("attempts") - .map(_.convertTo[Int]) - .getOrElse( - deserializationError(s"BridgeUploadQueue.Item json object does not contain `attempts` field: $json")) - - val nextAttempt = fields - .get("nextAttempt") - .map(_.convertTo[LocalDateTime]) - .getOrElse( - deserializationError(s"BridgeUploadQueue.Item json object does not contain `nextAttempt` field: $json")) - - BridgeUploadQueue.Item( - kind = kind, - tag = tag, - created = created, - attempts = attempts, - nextAttempt = nextAttempt, - completed = true, - dependencyKind = None, - dependencyTag = None - ) - - case _ => deserializationError(s"Expected Json Object as BridgeUploadQueue.Item, but got $json") - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/common.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/common.scala deleted file mode 100644 index 26adb9c..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/common.scala +++ /dev/null @@ -1,66 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.{LocalDate, LocalDateTime, ZoneId, ZonedDateTime} - -import spray.json._ -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} - -object common { - - implicit def longIdFormat[T] = new RootJsonFormat[LongId[T]] { - override def write(id: LongId[T]): JsNumber = JsNumber(id.id) - override def read(json: JsValue): LongId[T] = json match { - case JsNumber(value) => LongId(value.toLong) - case _ => deserializationError(s"Expected number as LongId, but got $json") - } - } - - implicit def stringIdFormat[T] = new RootJsonFormat[StringId[T]] { - override def write(id: StringId[T]): JsString = JsString(id.toString) - override def read(json: JsValue): StringId[T] = json match { - case JsString(value) => StringId(value) - case _ => deserializationError(s"Expected string as StringId, but got $json") - } - } - - implicit def uuidIdFormat[T] = new RootJsonFormat[UuidId[T]] { - override def write(id: UuidId[T]): JsString = JsString(id.toString) - override def read(json: JsValue): UuidId[T] = json match { - case JsString(value) => UuidId(value) - case _ => deserializationError(s"Expected string as UuidId, but got $json") - } - } - - implicit def dateTimeFormat = new RootJsonFormat[LocalDateTime] { - override def write(date: LocalDateTime): JsString = JsString(ZonedDateTime.of(date, ZoneId.of("Z")).toString) - override def read(json: JsValue): LocalDateTime = json match { - case JsString(value) => ZonedDateTime.parse(value).toLocalDateTime - case _ => deserializationError(s"Expected date as LocalDateTime, but got $json") - } - } - - implicit def zonedDateTimeFormat = new RootJsonFormat[ZonedDateTime] { - override def write(date: ZonedDateTime): JsString = JsString(date.toString) - override def read(json: JsValue): ZonedDateTime = json match { - case JsString(value) => ZonedDateTime.parse(value) - case _ => deserializationError(s"Expected date as ZonedDateTime, but got $json") - } - } - - implicit def dateFormat = new RootJsonFormat[LocalDate] { - override def write(date: LocalDate): JsString = JsString(date.toString) - override def read(json: JsValue): LocalDate = json match { - case JsString(value) => LocalDate.parse(value) - case _ => deserializationError(s"Expected date as LocalDate, but got $json") - } - } - - implicit val integerFormat: RootJsonFormat[Integer] = new RootJsonFormat[Integer] { - override def write(obj: Integer): JsNumber = JsNumber(obj.intValue()) - override def read(json: JsValue): Integer = json match { - case JsNumber(value) => value.toInt - case _ => deserializationError(s"Expected number as Integer, but got $json") - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion.scala deleted file mode 100644 index c4e89f0..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion.scala +++ /dev/null @@ -1,175 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.entities.labels.{Label, LabelCategory} -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.CriterionService.RichCriterion - -object criterion { - import DefaultJsonProtocol._ - import common._ - - implicit val criterionLabelWriter: RootJsonWriter[CriterionLabel] = new RootJsonWriter[CriterionLabel] { - override def write(obj: CriterionLabel) = JsObject( - "labelId" -> obj.labelId.toJson, - "categoryId" -> obj.categoryId.toJson, - "value" -> obj.value.map { - case true => "Yes" - case false => "No" - }.toJson, - "isDefining" -> obj.isDefining.toJson - ) - } - - def jsValueToCriterionLabel(json: JsValue, criterionId: LongId[Criterion]): CriterionLabel = json match { - case JsObject(fields) => - val labelId = fields - .get("labelId") - .flatMap(_.convertTo[Option[LongId[Label]]]) - - val categoryId = fields - .get("categoryId") - .flatMap(_.convertTo[Option[LongId[LabelCategory]]]) - - val value = fields - .get("value") - .flatMap(_.convertTo[Option[String]]) - .map { - case "Yes" => true - case "No" => false - case other => - deserializationError(s"Unknown `value` of CriterionLabel object: expected `yes` or `no`, but got $other") - } - - val isDefining = fields - .get("isDefining") - .map(_.convertTo[Boolean]) - .getOrElse(deserializationError(s"CriterionLabel json object does not contain `isDefining` field: $json")) - - CriterionLabel( - id = LongId(0L), - labelId = labelId, - criterionId = criterionId, - categoryId = categoryId, - value = value, - isDefining = isDefining - ) - - case _ => deserializationError(s"Expected Json Object as CriterionLabel, but got $json") - } - - def applyUpdateToCriterion(json: JsValue, orig: RichCriterion): RichCriterion = json match { - case JsObject(fields) => - val text = fields - .get("text") - .map(_.convertTo[String]) - - val isCompound = fields - .get("isCompound") - .exists(_.convertTo[Boolean]) - - val meta = fields - .get("meta") - .map(_.convertTo[Option[String]].getOrElse("{}")) - .getOrElse(orig.criterion.meta) - - val inclusion = fields - .get("inclusion") - .map(_.convertTo[Option[Boolean]]) - .getOrElse(orig.criterion.inclusion) - - val arms = fields - .get("arms") - .map(_.convertTo[Option[List[LongId[EligibilityArm]]]].getOrElse(List.empty[LongId[EligibilityArm]])) - .getOrElse(orig.armIds) - - val labels = fields - .get("labels") - .map(_.convertTo[Option[List[JsValue]]].getOrElse(List.empty[JsValue])) - .map(_.map(l => jsValueToCriterionLabel(l, orig.criterion.id))) - .getOrElse(orig.labels) - - orig.copy( - criterion = orig.criterion.copy( - meta = meta, - text = text, - isCompound = isCompound, - inclusion = inclusion - ), - armIds = arms, - labels = labels - ) - - case _ => deserializationError(s"Expected Json Object as partial Criterion, but got $json") - } - - implicit val richCriterionFormat: RootJsonFormat[RichCriterion] = new RootJsonFormat[RichCriterion] { - override def write(obj: RichCriterion): JsValue = - JsObject( - "id" -> obj.criterion.id.toJson, - "meta" -> Option(obj.criterion.meta).toJson, - "arms" -> obj.armIds.toJson, - "text" -> obj.criterion.text.toJson, - "isCompound" -> obj.criterion.isCompound.toJson, - "labels" -> obj.labels.map(_.toJson).toJson, - "trialId" -> obj.criterion.trialId.toJson, - "inclusion" -> obj.criterion.inclusion.toJson - ) - - override def read(json: JsValue): RichCriterion = json match { - case JsObject(fields) => - val id = fields - .get("id") - .flatMap(_.convertTo[Option[LongId[Criterion]]]) - - val trialId = fields - .get("trialId") - .map(_.convertTo[StringId[Trial]]) - .getOrElse(deserializationError(s"Criterion json object does not contain `trialId` field: $json")) - - val text = fields - .get("text") - .flatMap(_.convertTo[Option[String]]) - - val isCompound = fields - .get("isCompound") - .exists(_.convertTo[Boolean]) - - val meta = fields - .get("meta") - .flatMap(_.convertTo[Option[String]]) - - val inclusion = fields - .get("inclusion") - .flatMap(_.convertTo[Option[Boolean]]) - - val arms = fields - .get("arms") - .map(_.convertTo[Seq[LongId[EligibilityArm]]]) - .getOrElse(Seq.empty[LongId[EligibilityArm]]) - - val labels = fields - .get("labels") - .map(_.convertTo[Seq[JsValue]]) - .map(_.map(l => jsValueToCriterionLabel(l, LongId(0)))) - .getOrElse(Seq.empty[CriterionLabel]) - - RichCriterion( - criterion = Criterion( - id = id.getOrElse(LongId(0)), - trialId = trialId, - text = text, - isCompound = isCompound, - meta = meta.getOrElse(""), - inclusion = inclusion - ), - armIds = arms, - labels = labels - ) - - case _ => deserializationError(s"Expected Json Object as Criterion, but got $json") - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/document.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/document.scala deleted file mode 100644 index 66e95f3..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/document.scala +++ /dev/null @@ -1,221 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.{LocalDate, LocalDateTime} - -import spray.json._ -import xyz.driver.core.json._ -import xyz.driver.pdsuicommon.domain.{LongId, TextJson} -import xyz.driver.pdsuidomain.entities._ - -object document { - import DefaultJsonProtocol._ - import Document._ - import common._ - - implicit val documentStatusFormat: RootJsonFormat[Status] = new EnumJsonFormat[Status]( - "New" -> Status.New, - "Organized" -> Status.Organized, - "Extracted" -> Status.Extracted, - "Done" -> Status.Done, - "Flagged" -> Status.Flagged, - "Archived" -> Status.Archived - ) - - implicit val requiredTypeFormat: RootJsonFormat[RequiredType] = new EnumJsonFormat[RequiredType]( - "OPN" -> RequiredType.OPN, - "PN" -> RequiredType.PN - ) - - implicit val documentMetaFormat: RootJsonFormat[Meta] = jsonFormat2(Meta.apply) - - implicit val documentTypeFormat: RootJsonFormat[DocumentType] = new RootJsonFormat[DocumentType] { - override def read(json: JsValue): DocumentType = json match { - case JsObject(fields) => - val name = fields - .get("name") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"Document type json object does not contain `name` field: $json")) - - DocumentType - .fromString(name) - .getOrElse(deserializationError(s"Unknown document type: $name")) - - case _ => deserializationError(s"Expected Json Object as Document type, but got $json") - } - - override def write(obj: DocumentType) = - JsObject("id" -> obj.id.toJson, "name" -> obj.name.toJson) - } - - implicit val fullDocumentMetaFormat = new RootJsonFormat[TextJson[Meta]] { - override def write(obj: TextJson[Meta]): JsValue = obj.content.toJson - override def read(json: JsValue) = TextJson(documentMetaFormat.read(json)) - } - - def applyUpdateToDocument(json: JsValue, orig: Document): Document = json match { - case JsObject(fields) => - val physician = fields - .get("physician") - .map(_.convertTo[String]) - - val typeId = fields - .get("typeId") - .map(_.convertTo[Option[LongId[DocumentType]]]) - .getOrElse(orig.typeId) - - val provider = fields - .get("provider") - .map(_.convertTo[Option[String]]) - .getOrElse(orig.providerName) - - val providerTypeId = fields - .get("providerTypeId") - .map(_.convertTo[Option[LongId[ProviderType]]]) - .getOrElse(orig.providerTypeId) - - val institutionName = fields - .get("institutionName") - .map(_.convertTo[Option[String]]) - .getOrElse(orig.institutionName) - - val meta = fields - .get("meta") - .map(_.convertTo[Option[TextJson[Meta]]]) - .getOrElse(orig.meta) - - val startDate = fields - .get("startDate") - .map(_.convertTo[Option[LocalDate]]) - .getOrElse(orig.startDate) - - val endDate = fields - .get("endDate") - .map(_.convertTo[Option[LocalDate]]) - .getOrElse(orig.endDate) - - orig.copy( - physician = physician.orElse(orig.physician), - typeId = typeId, - providerName = provider, - providerTypeId = providerTypeId, - institutionName = institutionName, - meta = meta, - startDate = startDate, - endDate = endDate - ) - - case _ => deserializationError(s"Expected Json Object as partial Document, but got $json") - } - - implicit val documentFormat: RootJsonFormat[Document] = new RootJsonFormat[Document] { - override def write(document: Document): JsValue = - JsObject( - "id" -> document.id.toJson, - "recordId" -> document.recordId.toJson, - "physician" -> document.physician.toJson, - "typeId" -> document.typeId.toJson, - "provider" -> document.providerName.toJson, - "providerTypeId" -> document.providerTypeId.toJson, - "requiredType" -> document.requiredType.toJson, - "institutionName" -> document.institutionName.toJson, - "startDate" -> document.startDate.toJson, - "endDate" -> document.endDate.toJson, - "status" -> document.status.toJson, - "previousStatus" -> document.previousStatus.toJson, - "assignee" -> document.assignee.toJson, - "previousAssignee" -> document.previousAssignee.toJson, - "meta" -> document.meta.toJson, - "lastActiveUser" -> document.lastActiveUserId.toJson, - "lastUpdate" -> document.lastUpdate.toJson, - "labelVersion" -> document.labelVersion.toJson - ) - - override def read(json: JsValue): Document = json match { - case JsObject(fields) => - val id = fields - .get("id") - .flatMap(_.convertTo[Option[LongId[Document]]]) - - val recordId = fields - .get("recordId") - .map(_.convertTo[LongId[MedicalRecord]]) - .getOrElse(deserializationError(s"Document create json object does not contain `recordId` field: $json")) - - val status = fields - .get("status") - .flatMap(_.convertTo[Option[Document.Status]]) - - val previousStatus = fields - .get("previousStatus") - .flatMap(_.convertTo[Option[Document.Status]]) - - val physician = fields - .get("physician") - .flatMap(_.convertTo[Option[String]]) - - val typeId = fields - .get("typeId") - .flatMap(_.convertTo[Option[LongId[DocumentType]]]) - - val requiredType = fields - .get("requiredType") - .flatMap(_.convertTo[Option[Document.RequiredType]]) - - val provider = fields - .get("provider") - .flatMap(_.convertTo[Option[String]]) - - val providerTypeId = fields - .get("providerTypeId") - .flatMap(_.convertTo[Option[LongId[ProviderType]]]) - - val institutionName = fields - .get("institutionName") - .flatMap(_.convertTo[Option[String]]) - - val meta = fields - .get("meta") - .flatMap(_.convertTo[Option[TextJson[Meta]]]) - - val startDate = fields - .get("startDate") - .flatMap(_.convertTo[Option[LocalDate]]) - - val endDate = fields - .get("endDate") - .flatMap(_.convertTo[Option[LocalDate]]) - - val lastUpdate = fields - .get("lastUpdate") - .flatMap(_.convertTo[Option[LocalDateTime]]) - - val labelVersion = fields - .get("labelVersion") - .flatMap(_.convertTo[Option[Int]]) - - Document( - id = id.getOrElse(LongId(0)), - recordId = recordId, - status = status.getOrElse(Document.Status.New), - physician = physician, - typeId = typeId, - startDate = startDate, - endDate = endDate, - providerName = provider, - providerTypeId = providerTypeId, - requiredType = requiredType, - institutionName = institutionName, - meta = meta, - previousStatus = previousStatus, - assignee = None, - previousAssignee = None, - lastActiveUserId = None, - lastUpdate = lastUpdate.getOrElse(LocalDateTime.MIN), - labelVersion = labelVersion.getOrElse(0) - ) - - case _ => deserializationError(s"Expected Json Object as Document, but got $json") - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/documenthistory.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/documenthistory.scala deleted file mode 100644 index 1652f7b..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/documenthistory.scala +++ /dev/null @@ -1,35 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.core.json._ -import xyz.driver.pdsuidomain.entities._ - -object documenthistory { - import DefaultJsonProtocol._ - import DocumentHistory._ - import common._ - - implicit val documentStateFormat = new EnumJsonFormat[State]( - "New" -> State.New, - "Extract" -> State.Extract, - "Done" -> State.Done, - "Review" -> State.Review, - "Flag" -> State.Flag, - "Archive" -> State.Archive - ) - - implicit val documentActionFormat = new EnumJsonFormat[Action]( - "Start" -> Action.Start, - "Submit" -> Action.Submit, - "Unassign" -> Action.Unassign, - "Resolve" -> Action.Resolve, - "Flag" -> Action.Flag, - "Archive" -> Action.Archive, - "PostEvidence" -> Action.PostEvidence, - "CreateDocument" -> Action.CreateDocument, - "ReadDocument" -> Action.ReadDocument - ) - - implicit val documentHistoryFormat: RootJsonFormat[DocumentHistory] = jsonFormat6(DocumentHistory.apply) - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/documentissue.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/documentissue.scala deleted file mode 100644 index 037a3ad..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/documentissue.scala +++ /dev/null @@ -1,72 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import xyz.driver.core.auth.User -import xyz.driver.core.json._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities._ - -object documentissue { - import DefaultJsonProtocol._ - import common._ - - def applyUpdateToDocumentIssue(json: JsValue, orig: DocumentIssue): DocumentIssue = json match { - case JsObject(fields) => - val text = fields - .get("text") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"DocumentIssue json object does not contain `text` field: $json")) - - val archiveRequired = fields - .get("archiveRequired") - .map(_.convertTo[Boolean]) - .getOrElse(deserializationError(s"DocumentIssue json object does not contain `archiveRequired` field: $json")) - - val startPage = fields.get("startPage").map(_.convertTo[Option[Double]]) - val endPage = fields.get("endPage").map(_.convertTo[Option[Double]]) - - orig.copy( - text = text, - archiveRequired = archiveRequired, - startPage = startPage.getOrElse(orig.startPage), - endPage = endPage.getOrElse(orig.endPage) - ) - - case _ => deserializationError(s"Expected Json Object as partial DocumentIssue, but got $json") - - } - - def jsValueToDocumentIssue(json: JsValue, - documentId: LongId[Document], - userId: xyz.driver.core.Id[User]): DocumentIssue = - json match { - case JsObject(fields) => - val text = fields - .get("text") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"DocumentIssue json object does not contain `text` field: $json")) - - val id = fields.get("id").map(_.convertTo[LongId[DocumentIssue]]) - val startPage = fields.get("startPage").flatMap(_.convertTo[Option[Double]]) - val endPage = fields.get("endPage").flatMap(_.convertTo[Option[Double]]) - - DocumentIssue( - id = id.getOrElse(LongId(0)), - userId = userId, - documentId = documentId, - lastUpdate = LocalDateTime.MIN, - isDraft = true, - text = text, - archiveRequired = false, - startPage = startPage, - endPage = endPage - ) - - case _ => deserializationError(s"Expected Json Object as DocumentIssue, but got $json") - } - - implicit val documentIssueFormat: RootJsonFormat[DocumentIssue] = jsonFormat9(DocumentIssue.apply) - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibility.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibility.scala deleted file mode 100644 index 925ba65..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibility.scala +++ /dev/null @@ -1,108 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json.DefaultJsonProtocol._ -import spray.json._ -import DefaultJsonProtocol._ -import xyz.driver.core.Id -import xyz.driver.core.json._ -import xyz.driver.entities.labels.LabelValue -import xyz.driver.pdsuidomain.entities.eligibility._ - -object eligibility { - import export._ - import xyz.driver.formats.json.assay._ - import xyz.driver.formats.json.common._ - import xyz.driver.formats.json.labels._ - import xyz.driver.formats.json.process._ - import xyz.driver.pdsuidomain.formats.json.document._ - import xyz.driver.pdsuidomain.formats.json.record._ - import xyz.driver.pdsuidomain.formats.json.export._ - - implicit val molecularDocumentFormat: RootJsonFormat[MolecularEvidenceDocument] = jsonFormat7( - MolecularEvidenceDocument) - implicit val clinicalDocumentFormat: RootJsonFormat[ClinicalEvidenceDocument] = jsonFormat7(ClinicalEvidenceDocument) - - implicit val evidenceDocumentFormat: RootJsonFormat[EvidenceDocument] = - GadtJsonFormat.create[EvidenceDocument]("evidenceDocumentType") { - case _: MolecularEvidenceDocument => "Molecular" - case _: ClinicalEvidenceDocument => "Clinical" - } { - case "Molecular" => molecularDocumentFormat - case "Clinical" => clinicalDocumentFormat - } - - implicit object evidenceFormat extends RootJsonFormat[Evidence] { - - override def write(evidence: Evidence): JsValue = { - JsObject( - "evidenceId" -> evidence.evidenceId.toJson, - "evidenceText" -> evidence.evidenceText.toJson, - "labelValue" -> evidence.labelValue.toJson, - "document" -> evidence.document.toJson, - "isPrimaryValue" -> evidence.isPrimaryValue.toJson - ) - } - - override def read(json: JsValue): Evidence = { - json match { - case JsObject(fields) => - val evidenceId = fields - .get("evidenceId") - .map(_.convertTo[Id[Evidence]]) - - val evidenceText = fields - .get("evidenceText") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"Evidence json object do not contain 'evidenceText' field: $json")) - - val labelValue = fields - .get("labelValue") - .map(_.convertTo[LabelValue]) - .getOrElse(deserializationError(s"Evidence json object do not contain 'labelValue' field: $json")) - - val isDriverDocument = fields - .get("document") - .flatMap { - case JsObject(fieldMap) => - fieldMap - .get("isDriverDocument") - .map(_.convertTo[Boolean]) - case _ => deserializationError(s"Expected Json Object as 'isDriverDocument', but got $json") - } - .getOrElse(deserializationError(s"Evidence json object do not contain 'document' field: $json")) - - val document = customDocumentParser(isDriverDocument, fields, json) - - val isPrimaryValue = fields - .get("isPrimaryValue") - .map(_.convertTo[Option[Boolean]]) - .getOrElse(deserializationError(s"Evidence json object do not contain 'isPrimaryValue' field: $json")) - - Evidence(evidenceId, evidenceText, labelValue, document, isPrimaryValue) - case _ => deserializationError(s"Expected Json Object as 'Evidence', but got $json") - } - } - - def customDocumentParser(isDriverDocument: Boolean, - fields: Map[String, JsValue], - json: JsValue): EvidenceDocument = { - fields.get("document").fold { deserializationError(s"Expected Json Object as 'Document', but got $json") } { - document => - if (isDriverDocument) document.convertTo[MolecularEvidenceDocument] - else document.convertTo[ClinicalEvidenceDocument] - } - } - } - - implicit def labelWithEvidenceJsonFormat: RootJsonFormat[LabelEvidence] = jsonFormat2(LabelEvidence) - - implicit def labelRankingFormat: RootJsonFormat[LabelMismatchRank] = jsonFormat4(LabelMismatchRank) - implicit def labelRankingsFormat: RootJsonFormat[MismatchRankedLabels] = jsonFormat2(MismatchRankedLabels) - - implicit def matchedPatientFormat: RootJsonFormat[MatchedPatient] = jsonFormat6(MatchedPatient) - - implicit lazy val eligibleTrialFormat: RootJsonFormat[EligibleTrial] = jsonFormat2(EligibleTrial.apply) - implicit lazy val eligibleArmFormat: RootJsonFormat[EligibleArm] = jsonFormat2(EligibleArm.apply) - implicit lazy val eligibleCriterionFormat: RootJsonFormat[EligibleCriterion] = jsonFormat2(EligibleCriterion.apply) - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm.scala deleted file mode 100644 index 5827f62..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm.scala +++ /dev/null @@ -1,107 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.entities.patient.CancerType -import xyz.driver.formats.json.patient._ -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities._ - -object eligibilityarm { - - import DefaultJsonProtocol._ - import common._ - - private def deserializationErrorFieldMessage(field: String, json: JsValue)(implicit className: String) = { - deserializationError(s"$className json object do not contain '$field' field: $json") - } - - private def deserializationErrorEntityMessage(json: JsValue)(implicit className: String) = { - deserializationError(s"Expected Json Object as $className, but got $json") - } - - implicit def eligibilityArmWithDiseasesWriter: RootJsonWriter[EligibilityArmWithDiseases] = - new RootJsonWriter[EligibilityArmWithDiseases] { - override def write(obj: EligibilityArmWithDiseases): JsValue = { - JsObject( - "id" -> obj.eligibilityArm.id.toJson, - "name" -> obj.eligibilityArm.name.toJson, - "originalName" -> obj.eligibilityArm.originalName.toJson, - "trialId" -> obj.eligibilityArm.trialId.toJson, - "diseases" -> obj.eligibilityArmDiseases.map(_.disease.toJson).toJson - ) - } - } - - implicit def eligibilityArmWithDiseasesReader: RootJsonReader[EligibilityArmWithDiseases] = { - new RootJsonReader[EligibilityArmWithDiseases] { - implicit val className: String = "create EligibilityArmWithDiseases" - - override def read(json: JsValue): EligibilityArmWithDiseases = { - json match { - case JsObject(fields) => - val id = fields - .get("id") - .flatMap(_.convertTo[Option[LongId[EligibilityArm]]]) - - val name = fields - .get("name") - .map(_.convertTo[String]) - .getOrElse(deserializationErrorFieldMessage("name", json)) - - val trialId = fields - .get("trialId") - .map(_.convertTo[StringId[Trial]]) - .getOrElse(deserializationErrorFieldMessage("trialId", json)) - - val diseases = fields - .get("diseases") - .map(_.convertTo[Seq[String]]) - .getOrElse(deserializationErrorFieldMessage("diseases", json)) - - val eligibilityArm = EligibilityArm( - id = id.getOrElse(LongId(0)), - name = name, - trialId = trialId, - originalName = name - ) - - EligibilityArmWithDiseases( - eligibilityArm, - diseases.map { disease => - val condition = CancerType - .fromString(disease) - .getOrElse(throw new NoSuchElementException(s"unknown condition $disease")) - EligibilityArmDisease(eligibilityArm.id, condition) - } - ) - case _ => deserializationErrorEntityMessage(json) - } - } - } - } - - def applyUpdateToEligibilityArmWithDiseases(json: JsValue, - orig: EligibilityArmWithDiseases): EligibilityArmWithDiseases = { - implicit val className: String = "update EligibilityArmWithDiseases" - json match { - case JsObject(fields) => - val name = fields - .get("name") - .map(_.convertTo[String]) - .getOrElse(orig.eligibilityArm.name) - - val diseases = fields - .get("diseases") - .map(_.convertTo[Seq[CancerType]].map(x => EligibilityArmDisease(orig.eligibilityArm.id, x))) - .getOrElse(orig.eligibilityArmDiseases) - - orig.copy( - eligibilityArm = orig.eligibilityArm - .copy(name = name), - eligibilityArmDiseases = diseases - ) - - case _ => deserializationErrorEntityMessage(json) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/export.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/export.scala deleted file mode 100644 index 8fb7d03..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/export.scala +++ /dev/null @@ -1,127 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.core.json.idFormat -import xyz.driver.entities.labels.Label -import xyz.driver.formats.json.labels._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities.export.patient._ -import xyz.driver.pdsuidomain.entities.export.trial.{ExportTrialArm, ExportTrialLabelCriterion, ExportTrialWithLabels} -import xyz.driver.pdsuidomain.entities.{Criterion, EligibilityArm} - -object export { - import DefaultJsonProtocol._ - import common._ - import document._ - import record._ - - private def deserializationErrorFieldMessage(field: String, json: JsValue)(implicit className: String) = { - deserializationError(s"$className json object do not contain '$field' field: $json") - } - - private def deserializationErrorEntityMessage(json: JsValue)(implicit className: String) = { - deserializationError(s"Expected Json Object as $className, but got $json") - } - - implicit val patientLabelEvidenceDocumentFormat: RootJsonFormat[ExportPatientLabelEvidenceDocument] = - jsonFormat5(ExportPatientLabelEvidenceDocument.apply) - - implicit val patientLabelEvidenceFormat: RootJsonFormat[ExportPatientLabelEvidence] = - jsonFormat(ExportPatientLabelEvidence.apply, "evidenceId", "labelValue", "evidenceText", "document") - - implicit val patientLabelFormat: RootJsonFormat[ExportPatientLabel] = - jsonFormat(ExportPatientLabel.apply, "labelId", "evidence") - - implicit val patientWithLabelsFormat: RootJsonFormat[ExportPatientWithLabels] = - jsonFormat(ExportPatientWithLabels.apply, "patientId", "labelVersion", "labels") - - implicit val trialArmFormat: RootJsonFormat[ExportTrialArm] = jsonFormat3(ExportTrialArm.apply) - - implicit val trialLabelCriterionFormat: RootJsonFormat[ExportTrialLabelCriterion] = - new RootJsonFormat[ExportTrialLabelCriterion] { - implicit val className: String = "ExportTrialLabelCriterion" - - override def write(obj: ExportTrialLabelCriterion): JsValue = - JsObject( - "value" -> obj.value - .map { - case true => "Yes" - case false => "No" - } - .getOrElse("Unknown") - .toJson, - "labelId" -> obj.labelId.toJson, - "criterionId" -> obj.criterionId.toJson, - "criterionText" -> obj.criteria.toJson, - "armIds" -> obj.armIds.toJson, - "isCompound" -> obj.isCompound.toJson, - "isDefining" -> obj.isDefining.toJson, - "inclusion" -> obj.inclusion.toJson - ) - - override def read(json: JsValue): ExportTrialLabelCriterion = { - json match { - case JsObject(fields) => - val value = fields - .get("value") - .map(_.convertTo[String]) - .map { - case "Yes" => Option(true) - case "No" => Option(false) - case "Unknown" => Option.empty[Boolean] - } - .getOrElse(deserializationErrorFieldMessage("value", json)) - - val labelId = fields - .get("labelId") - .map(_.convertTo[LongId[Label]]) - .getOrElse(deserializationErrorFieldMessage("labelId", json)) - - val criterionId = fields - .get("criterionId") - .map(_.convertTo[LongId[Criterion]]) - .getOrElse(deserializationErrorFieldMessage("criterionId", json)) - - val criterionText = fields - .get("criterionText") - .map(_.convertTo[String]) - .getOrElse(deserializationErrorFieldMessage("criterionText", json)) - - val armIds = fields - .get("armIds") - .map(_.convertTo[Set[LongId[EligibilityArm]]]) - .getOrElse(deserializationErrorFieldMessage("armIds", json)) - - val isCompound = fields - .get("isCompound") - .map(_.convertTo[Boolean]) - .getOrElse(deserializationErrorFieldMessage("isCompound", json)) - - val isDefining = fields - .get("isDefining") - .map(_.convertTo[Boolean]) - .getOrElse(deserializationErrorFieldMessage("isDefining", json)) - - val inclusion = fields - .get("inclusion") - .flatMap(_.convertTo[Option[Boolean]]) - - ExportTrialLabelCriterion( - criterionId, - value, - labelId, - armIds, - criterionText, - isCompound, - isDefining, - inclusion - ) - - case _ => deserializationErrorEntityMessage(json) - } - } - } - - implicit val trialWithLabelsFormat: RootJsonFormat[ExportTrialWithLabels] = - jsonFormat(ExportTrialWithLabels.apply, "nctId", "trialId", "lastReviewed", "labelVersion", "arms", "criteria") -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata.scala deleted file mode 100644 index 232bb39..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata.scala +++ /dev/null @@ -1,155 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.entities.labels.{Label, LabelCategory, LabelValue} -import xyz.driver.formats.json.labels._ -import xyz.driver.pdsuicommon.domain.{LongId, TextJson} -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.ExtractedDataService.RichExtractedData - -object extracteddata { - import DefaultJsonProtocol._ - import ExtractedData._ - import common._ - - implicit val metaKeywordFormat: RootJsonFormat[Meta.Keyword] = jsonFormat4(Meta.Keyword) - implicit val metaTextLayerPositionFormat: RootJsonFormat[Meta.TextLayerPosition] = jsonFormat3( - Meta.TextLayerPosition) - implicit val metaEvidenceFormat: RootJsonFormat[Meta.Evidence] = jsonFormat3(Meta.Evidence) - - implicit val extractedDataMetaFormat: RootJsonFormat[Meta] = jsonFormat2(Meta.apply) - implicit val fullExtractedDataMetaFormat = new RootJsonFormat[TextJson[Meta]] { - override def write(obj: TextJson[Meta]): JsValue = obj.content.toJson - override def read(json: JsValue): TextJson[Meta] = TextJson(extractedDataMetaFormat.read(json)) - } - - implicit val extractedDataLabelWriter: JsonWriter[ExtractedDataLabel] = new JsonWriter[ExtractedDataLabel] { - override def write(label: ExtractedDataLabel): JsObject = { - JsObject( - "id" -> label.labelId.toJson, - "categoryId" -> label.categoryId.toJson, - "value" -> label.value.toJson - ) - } - } - - def applyLabelsForExtractedData(json: JsValue, dataId: LongId[ExtractedData]): ExtractedDataLabel = json match { - case JsObject(fields) => - val labelId = fields - .get("id") - .flatMap(_.convertTo[Option[LongId[Label]]]) - - val categoryId = fields - .get("categoryId") - .flatMap(_.convertTo[Option[LongId[LabelCategory]]]) - - val value = fields - .get("value") - .flatMap(_.convertTo[Option[LabelValue]]) - - ExtractedDataLabel( - id = LongId(0), - dataId = dataId, - labelId = labelId, - categoryId = categoryId, - value = value - ) - - case _ => deserializationError(s"Expected Json Object as ExtractedDataLabel, but got $json") - } - - def applyUpdateToExtractedData(json: JsValue, orig: RichExtractedData): RichExtractedData = json match { - case JsObject(fields) => - val keywordId = fields - .get("keywordId") - .map(_.convertTo[Option[LongId[Keyword]]]) - .getOrElse(orig.extractedData.keywordId) - - val evidence = fields - .get("evidence") - .map(_.convertTo[Option[String]]) - .getOrElse(orig.extractedData.evidenceText) - - val meta = fields - .get("meta") - .map(_.convertTo[Option[TextJson[Meta]]]) - .getOrElse(orig.extractedData.meta) - - val labels = fields - .get("labels") - .map( - _.convertTo[Option[List[JsValue]]] - .getOrElse(List.empty[JsValue]) - .map(l => applyLabelsForExtractedData(l, orig.extractedData.id))) - .getOrElse(orig.labels) - - val extractedData = orig.extractedData.copy( - keywordId = keywordId, - evidenceText = evidence, - meta = meta - ) - - orig.copy( - extractedData = extractedData, - labels = labels - ) - - case _ => deserializationError(s"Expected Json Object as partial ExtractedData, but got $json") - } - - implicit val extractedDataFormat: RootJsonFormat[RichExtractedData] = new RootJsonFormat[RichExtractedData] { - override def write(richData: RichExtractedData): JsValue = - JsObject( - "id" -> richData.extractedData.id.toJson, - "documentId" -> richData.extractedData.documentId.toJson, - "keywordId" -> richData.extractedData.keywordId.toJson, - "evidence" -> richData.extractedData.evidenceText.toJson, - "meta" -> richData.extractedData.meta.toJson, - "labels" -> richData.labels.map(_.toJson).toJson - ) - - override def read(json: JsValue): RichExtractedData = json match { - case JsObject(fields) => - val id = fields - .get("id") - .flatMap(_.convertTo[Option[LongId[ExtractedData]]]) - - val documentId = fields - .get("documentId") - .map(_.convertTo[LongId[Document]]) - .getOrElse( - deserializationError(s"ExtractedData create json object does not contain `documentId` field: $json")) - - val keywordId = fields - .get("keywordId") - .flatMap(_.convertTo[Option[LongId[Keyword]]]) - - val evidence = fields - .get("evidence") - .flatMap(_.convertTo[Option[String]]) - - val meta = fields - .get("meta") - .flatMap(_.convertTo[Option[TextJson[Meta]]]) - - val labels = fields - .get("labels") - .map(_.convertTo[List[JsValue]]) - .getOrElse(List.empty[JsValue]) - .map(l => applyLabelsForExtractedData(l, LongId(0))) - - val extractedData = ExtractedData( - id = id.getOrElse(LongId(0L)), - documentId = documentId, - keywordId = keywordId, - evidenceText = evidence, - meta = meta - ) - - RichExtractedData(extractedData, labels) - - case _ => deserializationError(s"Expected Json Object as ExtractedData, but got $json") - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/hypothesis.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/hypothesis.scala deleted file mode 100644 index c5f6141..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/hypothesis.scala +++ /dev/null @@ -1,12 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.pdsuidomain.entities._ - -object hypothesis { - import DefaultJsonProtocol._ - import common._ - - implicit val hypothesisFormat: RootJsonFormat[Hypothesis] = jsonFormat4(Hypothesis.apply) - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention.scala deleted file mode 100644 index bf528e6..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention.scala +++ /dev/null @@ -1,147 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities.InterventionType.DeliveryMethod -import xyz.driver.pdsuidomain.entities._ - -object intervention { - import DefaultJsonProtocol._ - import common._ - - implicit def interventionFormat: RootJsonFormat[InterventionWithArms] = new RootJsonFormat[InterventionWithArms] { - override def write(obj: InterventionWithArms) = - JsObject( - "id" -> obj.intervention.id.toJson, - "name" -> obj.intervention.name.toJson, - "typeId" -> obj.intervention.typeId.toJson, - "dosage" -> obj.intervention.dosage.toJson, - "isActive" -> obj.intervention.isActive.toJson, - "arms" -> obj.arms.map(_.armId).toJson, - "trialId" -> obj.intervention.trialId.toJson, - "deliveryMethod" -> obj.intervention.deliveryMethod.toJson, - "originalName" -> obj.intervention.originalName.toJson, - "originalDosage" -> obj.intervention.originalDosage.toJson, - "originalType" -> obj.intervention.originalType.toJson - ) - - override def read(json: JsValue): InterventionWithArms = json match { - case JsObject(fields) => - val trialId = fields - .get("trialId") - .map(_.convertTo[StringId[Trial]]) - .getOrElse(deserializationError(s"Intervention json object does not contain `trialId` field: $json")) - - val typeId = fields - .get("typeId") - .flatMap(_.convertTo[Option[LongId[InterventionType]]]) - - val name = fields - .get("name") - .map(_.convertTo[String]) - .getOrElse("") - - val dosage = fields - .get("dosage") - .map(_.convertTo[String]) - - val isActive = fields - .get("isActive") - .exists(_.convertTo[Boolean]) - - val deliveryMethod = fields - .get("deliveryMethod") - .flatMap(_.convertTo[Option[String]]) - - val arms = fields - .get("arms") - .map(_.convertTo[List[LongId[SlotArm]]]) - .map(_ map (x => InterventionArm(armId = x, interventionId = LongId(0L)))) - .getOrElse(List.empty[InterventionArm]) - - InterventionWithArms( - intervention = Intervention( - id = LongId(0L), - trialId = trialId, - name = name, - originalName = name, - typeId = typeId, - originalType = None, - dosage = dosage.getOrElse(""), - originalDosage = dosage.getOrElse(""), - isActive = isActive, - deliveryMethod = deliveryMethod - ), - arms = arms - ) - - case _ => deserializationError(s"Expected Json Object as create Intervention json, but got $json") - } - } - - def applyUpdateToInterventionWithArms(json: JsValue, orig: InterventionWithArms): InterventionWithArms = json match { - case JsObject(fields) => - val name = fields - .get("name") - .map(_.convertTo[String]) - - val typeId = fields - .get("typeId") - .map(_.convertTo[Option[LongId[InterventionType]]]) - - val dosage = fields - .get("dosage") - .map(_.convertTo[String]) - - val isActive = fields - .get("isActive") - .map(_.convertTo[Boolean]) - - val deliveryMethod = fields - .get("deliveryMethod") - .map(_.convertTo[Option[String]]) - .getOrElse(orig.intervention.deliveryMethod) - - val origIntervention = orig.intervention - val arms = fields - .get("arms") - .map(_.convertTo[List[LongId[SlotArm]]].map(x => InterventionArm(x, orig.intervention.id))) - - orig.copy( - intervention = origIntervention.copy( - name = name.getOrElse(origIntervention.name), - typeId = typeId.getOrElse(origIntervention.typeId), - dosage = dosage.getOrElse(origIntervention.dosage), - isActive = isActive.getOrElse(origIntervention.isActive), - deliveryMethod = deliveryMethod - ), - arms = arms.getOrElse(orig.arms) - ) - - case _ => deserializationError(s"Expected Json Object as partial Intervention, but got $json") - } - - implicit def interventionTypeFormat: JsonFormat[InterventionType] = new RootJsonFormat[InterventionType] { - override def read(json: JsValue): InterventionType = json match { - case JsObject(fields) => - val name = fields - .get("name") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"Intervention type json object does not contain `name` field: $json")) - - InterventionType - .typeFromString(name) - .getOrElse(deserializationError(s"Unknown intervention type: $name")) - - case _ => deserializationError(s"Expected Json Object as Intervention type, but got $json") - } - - override def write(obj: InterventionType) = - JsObject( - "id" -> obj.id.toJson, - "name" -> obj.name.toJson, - "deliveryMethods" -> obj.deliveryMethods.map(DeliveryMethod.methodToString).toJson - ) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/listresponse.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/listresponse.scala deleted file mode 100644 index 1e359d6..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/listresponse.scala +++ /dev/null @@ -1,45 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json.DefaultJsonProtocol._ -import spray.json._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.formats.json.common._ - -object listresponse { - private val itemsField = "items" - private val metaField = "meta" - - implicit val listResponseMetaFormat: RootJsonFormat[ListResponse.Meta] = jsonFormat4(ListResponse.Meta.apply) - - implicit def listResponseWriter[T: JsonWriter]: RootJsonWriter[ListResponse[T]] = - new RootJsonWriter[ListResponse[T]] { - override def write(listResponse: ListResponse[T]): JsValue = { - JsObject( - itemsField -> listResponse.items.map(_.toJson).toJson, - metaField -> listResponse.meta.toJson - ) - } - } - - implicit def listResponseReader[T: JsonReader]: RootJsonReader[ListResponse[T]] = - new RootJsonReader[ListResponse[T]] { - override def read(json: JsValue): ListResponse[T] = json match { - case JsObject(fields) => - val items = fields - .get(itemsField) - .map { - case JsArray(elements) => elements.map(_.convertTo[T])(collection.breakOut) - case x => deserializationError(s"Expected Array as JsArray, but got $x") - } - .getOrElse(deserializationError(s"ListResponse json object does not contain `$itemsField` field: $json")) - - val meta = fields - .get(metaField) - .map(_.convertTo[ListResponse.Meta]) - .getOrElse(deserializationError(s"ListResponse json object does not contain `$metaField` field: $json")) - - ListResponse(items, meta) - case _ => deserializationError(s"Expected ListResponse json object, but got $json") - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient.scala deleted file mode 100644 index 774a1ff..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient.scala +++ /dev/null @@ -1,118 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.{LocalDate, LocalDateTime} - -import spray.json._ -import xyz.driver.core.auth.User -import xyz.driver.core.json._ -import xyz.driver.entities.clinic.TestOrder -import xyz.driver.entities.common.FullName -import xyz.driver.entities.patient.CancerType -import xyz.driver.formats.json.common._ -import xyz.driver.formats.json.patient._ -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuidomain.entities._ - -object patient { - import DefaultJsonProtocol._ - import Patient._ - import common._ - - implicit val patientStatusFormat: RootJsonFormat[Status] = new EnumJsonFormat[Status]( - "New" -> Status.New, - "Verified" -> Status.Verified, - "Reviewed" -> Status.Reviewed, - "Curated" -> Status.Curated, - "Done" -> Status.Done, - "Flagged" -> Status.Flagged - ) - - implicit val patientFormat: RootJsonFormat[Patient] = new RootJsonFormat[Patient] { - override def write(patient: Patient): JsValue = - JsObject( - "id" -> patient.id.toJson, - "status" -> patient.status.toJson, - "name" -> patient.name.toJson, - "dob" -> patient.dob.toJson, - "assignee" -> patient.assignee.toJson, - "previousStatus" -> patient.previousStatus.toJson, - "previousAssignee" -> patient.previousAssignee.toJson, - "lastActiveUser" -> patient.lastActiveUserId.toJson, - "lastUpdate" -> patient.lastUpdate.toJson, - "disease" -> patient.disease.toJson, - "orderId" -> patient.orderId.toJson - ) - - override def read(json: JsValue): Patient = { - json match { - case JsObject(fields) => - val id = fields - .get("id") - .map(_.convertTo[UuidId[Patient]]) - .getOrElse(deserializationError(s"Patient create json object does not contain `id` field: $json")) - - val status = fields - .get("status") - .map(_.convertTo[Patient.Status]) - .getOrElse(deserializationError(s"Patient create json object does not contain `status` field: $json")) - - val name = fields - .get("name") - .map(_.convertTo[FullName[Patient]]) - .getOrElse(deserializationError(s"Patient create json object does not contain `name` field: $json")) - - val dob = fields - .get("dob") - .map(_.convertTo[LocalDate]) - .getOrElse(deserializationError(s"Patient create json object does not contain `dob` field: $json")) - - val assignee = fields - .get("assignee") - .flatMap(_.convertTo[Option[xyz.driver.core.Id[User]]]) - - val previousStatus = fields - .get("previousStatus") - .flatMap(_.convertTo[Option[Patient.Status]]) - - val previousAssignee = fields - .get("previousAssignee") - .flatMap(_.convertTo[Option[xyz.driver.core.Id[User]]]) - - val lastActiveUser = fields - .get("lastActiveUser") - .flatMap(_.convertTo[Option[xyz.driver.core.Id[User]]]) - - val disease = fields - .get("disease") - .map(_.convertTo[CancerType]) - .getOrElse(deserializationError(s"Patient create json object does not contain `disease` field: $json")) - - val orderId = fields - .get("orderId") - .map(_.convertTo[xyz.driver.core.Id[TestOrder]]) - .getOrElse(deserializationError(s"Patient create json object does not contain `orderId` field: $json")) - - val lastUpdate = fields - .get("lastUpdate") - .map(_.convertTo[LocalDateTime]) - .getOrElse(deserializationError(s"Patient create json object does not contain `lastUpdate` field: $json")) - - Patient(id, - status, - name, - dob, - assignee, - previousStatus, - previousAssignee, - lastActiveUser, - isUpdateRequired = false, - disease, - orderId, - lastUpdate) - - case _ => deserializationError(s"Expected Json Object as Trial, but got $json") - } - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientcriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientcriterion.scala deleted file mode 100644 index 035310b..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientcriterion.scala +++ /dev/null @@ -1,65 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.entities.labels.{Label, LabelValue} -import xyz.driver.formats.json.labels._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities._ - -object patientcriterion { - import DefaultJsonProtocol._ - import common._ - - def applyUpdateToPatientCriterion(json: JsValue, orig: PatientCriterion): PatientCriterion = json match { - case JsObject(fields) => - val eligibilityStatus = fields - .get("eligibilityStatus") - .map(_.convertTo[LabelValue]) - .getOrElse(orig.eligibilityStatus) - - val verifiedEligibilityStatus = fields - .get("verifiedEligibilityStatus") - .map(_.convertTo[LabelValue]) - .getOrElse(orig.verifiedEligibilityStatus) - - orig.copy( - eligibilityStatus = eligibilityStatus, - verifiedEligibilityStatus = verifiedEligibilityStatus - ) - - case _ => deserializationError(s"Expected Json Object as partial PatientCriterion, but got $json") - } - - implicit val draftPatientCriterionFormat: RootJsonFormat[DraftPatientCriterion] = jsonFormat3( - DraftPatientCriterion.apply) - implicit val draftPatientCriterionListReader = new JsonReader[List[DraftPatientCriterion]] { - override def read(json: JsValue) = json.convertTo[List[JsValue]].map(_.convertTo[DraftPatientCriterion]) - } - - implicit val patientCriterionFormat: RootJsonFormat[PatientCriterion] = jsonFormat14(PatientCriterion.apply) - implicit val patientCriterionArmFormat: RootJsonFormat[PatientCriterionArm] = jsonFormat3(PatientCriterionArm.apply) - - implicit val richPatientCriterionFormat: RootJsonFormat[RichPatientCriterion] = - new RootJsonFormat[RichPatientCriterion] { - override def read(json: JsValue): RichPatientCriterion = { - val fields = json.asJsObject.fields - val labelId = fields.getOrElse("labelId", deserializationError("field 'labelId' is missing")) - val arms = fields.getOrElse("armList", deserializationError("field 'arms' is missing")) - RichPatientCriterion( - json.convertTo[PatientCriterion], - labelId.convertTo[LongId[Label]], - arms.convertTo[List[PatientCriterionArm]] - ) - } - override def write(obj: RichPatientCriterion): JsValue = { - JsObject( - obj.patientCriterion.toJson.asJsObject.fields ++ - Map( - "labelId" -> obj.labelId.toJson, - "armList" -> obj.armList.toJson - ) - ) - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientdefiningcriteria.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientdefiningcriteria.scala deleted file mode 100644 index a67115c..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientdefiningcriteria.scala +++ /dev/null @@ -1,18 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.formats.json.labels._ -import xyz.driver.pdsuidomain.entities.PatientLabel - -object patientdefiningcriteria { - import common._ - - implicit val patientLabelDefiningCriteriaWriter: RootJsonWriter[PatientLabel] = new RootJsonWriter[PatientLabel] { - override def write(obj: PatientLabel) = - JsObject( - "id" -> obj.id.toJson, - "value" -> obj.verifiedPrimaryValue.toJson - ) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patienteligibletrial.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patienteligibletrial.scala deleted file mode 100644 index d719c5c..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patienteligibletrial.scala +++ /dev/null @@ -1,39 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.formats.json.labels._ -import xyz.driver.pdsuidomain.entities._ - -object patienteligibletrial { - import DefaultJsonProtocol._ - import common._ - - def applyUpdateToTrialArmGroup(json: JsValue, orig: PatientTrialArmGroupView): PatientTrialArmGroupView = - json match { - case JsObject(fields) => - val isVerified = fields - .get("isVerified") - .map(_.convertTo[Boolean]) - .getOrElse(orig.isVerified) - - orig.copy(isVerified = isVerified) - - case _ => deserializationError(s"Expected Json Object as partial PatientTrialArmGroupView, but got $json") - } - - implicit val patientEligibleTrialWriter: RootJsonWriter[RichPatientEligibleTrial] = - new RootJsonWriter[RichPatientEligibleTrial] { - override def write(obj: RichPatientEligibleTrial) = - JsObject( - "id" -> obj.group.id.toJson, - "patientId" -> obj.group.patientId.toJson, - "trialId" -> obj.group.trialId.toJson, - "trialTitle" -> obj.trial.title.toJson, - "arms" -> obj.arms.map(_.armName).toJson, - "hypothesisId" -> obj.trial.hypothesisId.toJson, - "verifiedEligibilityStatus" -> obj.group.verifiedEligibilityStatus.toJson, - "isVerified" -> obj.group.isVerified.toJson - ) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patienthistory.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patienthistory.scala deleted file mode 100644 index c9cdc63..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patienthistory.scala +++ /dev/null @@ -1,30 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.core.json._ -import xyz.driver.pdsuidomain.entities._ - -object patienthistory { - import DefaultJsonProtocol._ - import PatientHistory._ - import common._ - - implicit val patientStateFormat: RootJsonFormat[State] = new EnumJsonFormat[State]( - "Verify" -> State.Verify, - "Curate" -> State.Curate, - "Review" -> State.Review, - "Flag" -> State.Flag - ) - - implicit val patientActionFormat: RootJsonFormat[Action] = new EnumJsonFormat[Action]( - "Start" -> Action.Start, - "Submit" -> Action.Submit, - "Unassign" -> Action.Unassign, - "Resolve" -> Action.Resolve, - "Flag" -> Action.Flag, - "Archive" -> Action.Archive - ) - - implicit val patientHistoryFormat: RootJsonFormat[PatientHistory] = jsonFormat6(PatientHistory.apply) - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patienthypothesis.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patienthypothesis.scala deleted file mode 100644 index da991a4..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patienthypothesis.scala +++ /dev/null @@ -1,35 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.pdsuidomain.entities._ - -object patienthypothesis { - import DefaultJsonProtocol._ - import common._ - import xyz.driver.core.json._ - - def applyUpdateToPatientHypothesis(json: JsValue, orig: PatientHypothesis): PatientHypothesis = json match { - case JsObject(fields) => - val rationale = if (fields.contains("rationale")) { - fields.get("rationale").map(_.convertTo[String]) - } else orig.rationale - - orig.copy(rationale = rationale) - - case _ => deserializationError(s"Expected Json Object as partial PatientHypothesis, but got $json") - } - - implicit val patientHypothesisWriter: RootJsonWriter[PatientHypothesis] = - new RootJsonWriter[PatientHypothesis] { - override def write(obj: PatientHypothesis): JsValue = { - JsObject( - "id" -> obj.id.toJson, - "patientId" -> obj.patientId.toJson, - "hypothesisId" -> obj.hypothesisId.toJson, - "matchedTrials" -> obj.matchedTrials.toJson, - "rationale" -> obj.rationale.toJson - ) - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientissue.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientissue.scala deleted file mode 100644 index ed05325..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientissue.scala +++ /dev/null @@ -1,58 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import xyz.driver.core.auth.User -import xyz.driver.core.json._ -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuidomain.entities._ - -object patientissue { - import DefaultJsonProtocol._ - import common._ - - def applyUpdateToPatientIssue(json: JsValue, orig: PatientIssue): PatientIssue = { - json.asJsObject.getFields("text", "archiveRequired") match { - case Seq(text, archiveRequired) => - orig.copy( - text = text.convertTo[String], - archiveRequired = archiveRequired.convertTo[Boolean] - ) - - case _ => deserializationError(s"Expected Json Object as partial PatientIssue, but got $json") - } - } - - def jsValueToPatientIssue(json: JsValue, - patientId: UuidId[Patient], - userId: xyz.driver.core.Id[User]): PatientIssue = { - json.asJsObject.getFields("text") match { - case Seq(text) => - PatientIssue( - id = json.asJsObject.fields.get("id").flatMap(_.convertTo[Option[LongId[PatientIssue]]]).getOrElse(LongId(0)), - userId = userId, - patientId = patientId, - lastUpdate = LocalDateTime.MIN, - isDraft = true, - text = text.convertTo[String], - archiveRequired = false - ) - - case _ => deserializationError(s"Expected Json Object as PatientIssue, but got $json") - } - - } - - implicit val patientIssueWriter: RootJsonWriter[PatientIssue] = new RootJsonWriter[PatientIssue] { - override def write(obj: PatientIssue) = JsObject( - "id" -> obj.id.toJson, - "text" -> obj.text.toJson, - "lastUpdate" -> obj.lastUpdate.toJson, - "userId" -> obj.userId.toJson, - "isDraft" -> obj.isDraft.toJson, - "archiveRequired" -> obj.archiveRequired.toJson - ) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientlabel.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientlabel.scala deleted file mode 100644 index 615b3a2..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patientlabel.scala +++ /dev/null @@ -1,65 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.entities.labels.LabelValue -import xyz.driver.formats.json.labels._ -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.formats.json.labels._ -import xyz.driver.pdsuidomain.formats.json.record._ -import xyz.driver.pdsuidomain.formats.json.document._ - -object patientlabel { - import DefaultJsonProtocol._ - import common._ - - def applyUpdateToPatientLabel(json: JsValue, orig: PatientLabel): PatientLabel = json match { - case JsObject(fields) => - val primaryValue = fields - .get("primaryValue") - .map(_.convertTo[LabelValue]) - .getOrElse(orig.primaryValue) - - val verifiedPrimaryValue = fields - .get("verifiedPrimaryValue") - .map(_.convertTo[LabelValue]) - .getOrElse(orig.verifiedPrimaryValue) - - orig.copy( - primaryValue = primaryValue, - verifiedPrimaryValue = verifiedPrimaryValue - ) - - case _ => deserializationError(s"Expected Json Object as PatientLabel, but got $json") - } - - implicit val patientLabelFormat: RootJsonFormat[PatientLabel] = jsonFormat8(PatientLabel.apply) - - implicit val richPatientLabelFormat: RootJsonFormat[RichPatientLabel] = new RootJsonFormat[RichPatientLabel] { - override def read(json: JsValue): RichPatientLabel = { - val isVerified = - json.asJsObject.fields.getOrElse("isVerified", deserializationError("isVerified field is missing")) - RichPatientLabel(json.convertTo[PatientLabel], isVerified.convertTo[Boolean]) - } - override def write(obj: RichPatientLabel): JsValue = { - val labelFields = obj.patientLabel.toJson.asJsObject.fields - JsObject(labelFields ++ Map("isVerified" -> obj.isVerified.toJson)) - } - } - - implicit val patientLabelEvidenceWriter: RootJsonWriter[PatientLabelEvidenceView] = - new RootJsonWriter[PatientLabelEvidenceView] { - override def write(evidence: PatientLabelEvidenceView): JsValue = - JsObject( - "id" -> evidence.id.toJson, - "value" -> evidence.value.toJson, - "evidenceText" -> evidence.evidenceText.toJson, - "documentId" -> evidence.documentId.toJson, - "evidenceId" -> evidence.evidenceId.toJson, - "reportId" -> evidence.reportId.toJson, - "documentType" -> evidence.documentType.toJson, - "date" -> evidence.date.toJson, - "providerType" -> evidence.providerType.toJson - ) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/record.scala deleted file mode 100644 index d3fe2c9..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record.scala +++ /dev/null @@ -1,213 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import xyz.driver.core.Id -import xyz.driver.core.json._ -import xyz.driver.entities.clinic.ClinicalRecord -import xyz.driver.pdsuicommon.domain.{LongId, TextJson, UuidId} -import xyz.driver.pdsuidomain.entities.MedicalRecord.Meta._ -import xyz.driver.pdsuidomain.entities._ - -object record { - import DefaultJsonProtocol._ - import MedicalRecord._ - import common._ - - implicit val recordStatusFormat: EnumJsonFormat[Status] = new EnumJsonFormat[Status]( - "New" -> Status.New, - "Cleaned" -> Status.Cleaned, - "Reviewed" -> Status.Reviewed, - "Organized" -> Status.Organized, - "Done" -> Status.Done, - "Flagged" -> Status.Flagged, - "Archived" -> Status.Archived - ) - - implicit val providerTypeFormat: RootJsonFormat[ProviderType] = new RootJsonFormat[ProviderType] { - override def read(json: JsValue): ProviderType = json match { - case JsObject(fields) => - val name = fields - .get("name") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"Provider type json object does not contain `name` field: $json")) - - ProviderType - .fromString(name) - .getOrElse(deserializationError(s"Unknown provider type: $name")) - - case _ => deserializationError(s"Expected Json Object as Provider type, but got $json") - } - - override def write(obj: ProviderType) = - JsObject("id" -> obj.id.toJson, "name" -> obj.name.toJson) - } - - implicit val duplicateMetaFormat: RootJsonFormat[Duplicate] = new RootJsonFormat[Duplicate] { - override def write(obj: Duplicate) = - JsObject( - "type" -> "duplicate".toJson, - "startPage" -> obj.startPage.toJson, - "endPage" -> obj.endPage.toJson, - "startOriginalPage" -> obj.startOriginalPage.toJson, - "endOriginalPage" -> obj.endOriginalPage.toJson - ) - - override def read(json: JsValue): Duplicate = json match { - case JsObject(fields) => - val startPage = fields - .get("startPage") - .map(_.convertTo[Double]) - .getOrElse(deserializationError(s"Duplicate meta json object does not contain `startPage` field: $json")) - - val endPage = fields - .get("endPage") - .map(_.convertTo[Double]) - .getOrElse(deserializationError(s"Duplicate meta json object does not contain `endPage` field: $json")) - - val startOriginalPage = fields - .get("startOriginalPage") - .map(_.convertTo[Double]) - .getOrElse( - deserializationError(s"Duplicate meta json object does not contain `startOriginalPage` field: $json")) - - val endOriginalPage = fields - .get("endOriginalPage") - .flatMap(_.convertTo[Option[Double]]) - - Duplicate( - startPage = startPage, - endPage = endPage, - startOriginalPage = startOriginalPage, - endOriginalPage = endOriginalPage - ) - - case _ => deserializationError(s"Expected JsObject as Duplicate meta of medical record, but got $json") - } - } - - implicit val reorderMetaFormat: RootJsonFormat[Reorder] = new RootJsonFormat[Reorder] { - override def write(obj: Reorder) = - JsObject("type" -> "reorder".toJson, "items" -> obj.items.toJson) - - override def read(json: JsValue): Reorder = json match { - case JsObject(fields) => - val items = fields - .get("items") - .map(_.convertTo[Seq[Int]]) - .getOrElse(deserializationError(s"Reorder meta json object does not contain `items` field: $json")) - - Reorder(items) - - case _ => deserializationError(s"Expected JsObject as Reorder meta of medical record, but got $json") - } - } - - implicit val rotateMetaFormat: RootJsonFormat[Rotation] = new RootJsonFormat[Rotation] { - override def write(obj: Rotation) = - JsObject("type" -> "rotation".toJson, "items" -> obj.items.toJson) - - override def read(json: JsValue): Rotation = json match { - case JsObject(fields) => - val items = fields - .get("items") - .map(_.convertTo[Map[String, Int]]) - .getOrElse(deserializationError(s"Rotation meta json object does not contain `items` field: $json")) - - Rotation(items = items) - - case _ => deserializationError(s"Expected JsObject as Rotation meta of medical record, but got $json") - } - } - - implicit val recordMetaTypeFormat: GadtJsonFormat[MedicalRecord.Meta] = { - GadtJsonFormat.create[Meta]("type")({ case m => m.metaType }) { - case "duplicate" => duplicateMetaFormat - case "reorder" => reorderMetaFormat - case "rotation" => rotateMetaFormat - } - } - - implicit val recordMetaFormat: RootJsonFormat[TextJson[List[Meta]]] = new RootJsonFormat[TextJson[List[Meta]]] { - override def write(obj: TextJson[List[Meta]]): JsArray = JsArray(obj.content.map(_.toJson).toVector) - override def read(json: JsValue): TextJson[List[Meta]] = json match { - case JsArray(values) => TextJson[List[Meta]](values.map(_.convertTo[Meta]).toList) - case _ => deserializationError(s"Expected array as Meta, but got $json") - } - } - - implicit val recordFormat: RootJsonFormat[MedicalRecord] = - new RootJsonFormat[MedicalRecord] { - override def write(record: MedicalRecord): JsValue = - JsObject( - "id" -> record.id.toJson, - "patientId" -> record.patientId.toJson, - "caseId" -> record.caseId.toJson, - "disease" -> record.disease.toJson, - "physician" -> record.physician.toJson, - "status" -> record.status.toJson, - "previousStatus" -> record.previousStatus.toJson, - "assignee" -> record.assignee.toJson, - "previousAssignee" -> record.previousAssignee.toJson, - "requestId" -> record.requestId.toJson, - "meta" -> record.meta.getOrElse(TextJson[List[Meta]](List.empty)).toJson, - "lastActiveUser" -> record.lastActiveUserId.toJson, - "lastUpdate" -> record.lastUpdate.toJson, - "totalPages" -> record.totalPages.toJson - ) - - override def read(json: JsValue): MedicalRecord = json match { - case JsObject(fields) => - val id = fields - .get("id") - .flatMap(_.convertTo[Option[LongId[MedicalRecord]]]) - - val disease = fields - .get("disease") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"MedicalRecord json object does not contain `disease` field: $json")) - - val patientId = fields - .get("patientId") - .map(_.convertTo[UuidId[Patient]]) - .getOrElse(deserializationError(s"MedicalRecord json object does not contain `patientId` field: $json")) - - val requestId = fields - .get("requestId") - .map(_.convertTo[Id[ClinicalRecord]]) - .getOrElse(deserializationError(s"MedicalRecord json object does not contain `requestId` field: $json")) - - MedicalRecord( - id = id.getOrElse(LongId(0)), - status = MedicalRecord.Status.New, - previousStatus = None, - assignee = None, - previousAssignee = None, - lastActiveUserId = None, - patientId = patientId, - requestId = requestId, - disease = disease, - caseId = None, - physician = None, - meta = None, - lastUpdate = LocalDateTime.now(), - totalPages = 0 - ) - - case _ => deserializationError(s"Expected Json Object as MedicalRecord, but got $json") - } - } - - def applyUpdateToMedicalRecord(json: JsValue, orig: MedicalRecord): MedicalRecord = json match { - case JsObject(fields) => - val meta = fields - .get("meta") - .map(_.convertTo[Option[TextJson[List[Meta]]]]) - .getOrElse(orig.meta) - orig.copy(meta = meta) - - case _ => deserializationError(s"Expected Json Object as partial MedicalRecord, but got $json") - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/recordhistory.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/recordhistory.scala deleted file mode 100644 index be9dae9..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/recordhistory.scala +++ /dev/null @@ -1,43 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.core.json._ -import xyz.driver.pdsuidomain.entities._ - -object recordhistory { - import DefaultJsonProtocol._ - import MedicalRecordHistory._ - import common._ - - implicit val recordStateFormat = new EnumJsonFormat[State]( - "New" -> State.New, - "Clean" -> State.Clean, - "Organize" -> State.Organize, - "Review" -> State.Review, - "Done" -> State.Done, - "Flag" -> State.Flag, - "Archive" -> State.Archive - ) - - implicit val recordActionFormat = new EnumJsonFormat[Action]( - "Start" -> Action.Start, - "Submit" -> Action.Submit, - "Unassign" -> Action.Unassign, - "Resolve" -> Action.Resolve, - "Flag" -> Action.Flag, - "Archive" -> Action.Archive, - "SaveDuplicate" -> Action.SaveDuplicate, - "SaveReorder" -> Action.SaveReorder, - "SaveRotation" -> Action.SaveRotation, - "DeleteDuplicate" -> Action.DeleteDuplicate, - "DeleteReorder" -> Action.DeleteReorder, - "DeleteRotation" -> Action.DeleteRotation, - "CreateDocument" -> Action.CreateDocument, - "DeleteDocument" -> Action.DeleteDocument, - "CreateRecord" -> Action.CreateRecord, - "ReadRecord" -> Action.ReadRecord - ) - - implicit val recordHistoryFormat: RootJsonFormat[MedicalRecordHistory] = jsonFormat6(MedicalRecordHistory.apply) - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/recordissue.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/recordissue.scala deleted file mode 100644 index e7f2f65..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/recordissue.scala +++ /dev/null @@ -1,72 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import xyz.driver.core.auth.User -import xyz.driver.core.json._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities._ - -object recordissue { - import DefaultJsonProtocol._ - import common._ - - def applyUpdateToRecordIssue(json: JsValue, orig: MedicalRecordIssue): MedicalRecordIssue = json match { - case JsObject(fields) => - val text = fields - .get("text") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"MedicalRecordIssue json object does not contain `text` field: $json")) - - val archiveRequired = fields - .get("archiveRequired") - .map(_.convertTo[Boolean]) - .getOrElse( - deserializationError(s"MedicalRecordIssue json object does not contain `archiveRequired` field: $json")) - - val startPage = fields.get("startPage").map(_.convertTo[Double]) - val endPage = fields.get("endPage").map(_.convertTo[Double]) - - orig.copy( - text = text, - archiveRequired = archiveRequired, - startPage = startPage, - endPage = endPage - ) - - case _ => deserializationError(s"Expected Json Object as partial MedicalRecordIssue, but got $json") - - } - - def jsValueToRecordIssue(json: JsValue, - recordId: LongId[MedicalRecord], - userId: xyz.driver.core.Id[User]): MedicalRecordIssue = json match { - case JsObject(fields) => - val text = fields - .get("text") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"MedicalRecordIssue json object does not contain `text` field: $json")) - - val id = fields.get("id").flatMap(_.convertTo[Option[LongId[MedicalRecordIssue]]]).getOrElse(LongId(0)) - val startPage = fields.get("startPage").map(_.convertTo[Double]) - val endPage = fields.get("endPage").map(_.convertTo[Double]) - - MedicalRecordIssue( - id = id, - userId = userId, - recordId = recordId, - lastUpdate = LocalDateTime.MIN, - isDraft = true, - text = text, - archiveRequired = false, - startPage = startPage, - endPage = endPage - ) - - case _ => deserializationError(s"Expected Json Object as MedicalRecordIssue, but got $json") - } - - implicit val recordIssueFormat: RootJsonFormat[MedicalRecordIssue] = jsonFormat9(MedicalRecordIssue.apply) - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm.scala deleted file mode 100644 index 60d6521..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm.scala +++ /dev/null @@ -1,44 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities.{SlotArm, Trial} - -object slotarm { - import DefaultJsonProtocol._ - import common._ - - def applyUpdateToArm(json: JsValue, orig: SlotArm): SlotArm = json match { - case JsObject(fields) => - val name = fields - .get("name") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"Arm json object does not contain `name` field: $json")) - orig.copy(name = name) - - case _ => deserializationError(s"Expected Json Object as partial Arm, but got $json") - } - - implicit def slotArmFormat: RootJsonFormat[SlotArm] = new RootJsonFormat[SlotArm] { - override def write(obj: SlotArm): JsValue = - JsObject( - "id" -> obj.id.toJson, - "name" -> obj.name.toJson, - "originalName" -> obj.originalName.toJson, - "trialId" -> obj.trialId.toJson - ) - - override def read(json: JsValue): SlotArm = json.asJsObject.getFields("trialId", "name") match { - case Seq(trialId, name) => - SlotArm( - id = json.asJsObject.fields.get("id").flatMap(_.convertTo[Option[LongId[SlotArm]]]).getOrElse(LongId(0)), - name = name.convertTo[String], - trialId = trialId.convertTo[StringId[Trial]], - originalName = name.convertTo[String] - ) - - case _ => deserializationError(s"Expected Json Object as Arm, but got $json") - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/studydesign.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/studydesign.scala deleted file mode 100644 index 60c7e70..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/studydesign.scala +++ /dev/null @@ -1,29 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.pdsuidomain.entities._ - -object studydesign { - import DefaultJsonProtocol._ - import common._ - - implicit val studyDesignFormat: RootJsonFormat[StudyDesign] = new RootJsonFormat[StudyDesign] { - override def read(json: JsValue): StudyDesign = json match { - case JsObject(fields) => - val name = fields - .get("name") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"Study design json object does not contain `name` field: $json")) - - StudyDesign - .fromString(name) - .getOrElse(deserializationError(s"Unknown study design: $name")) - - case _ => deserializationError(s"Expected Json Object as Study design, but got $json") - } - - override def write(obj: StudyDesign) = - JsObject("id" -> obj.id.toJson, "name" -> obj.name.toJson) - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial.scala deleted file mode 100644 index cdc52d9..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial.scala +++ /dev/null @@ -1,187 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.{LocalDateTime, ZoneId, ZonedDateTime} - -import spray.json._ -import xyz.driver.core.auth.User -import xyz.driver.core.json._ -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} -import xyz.driver.pdsuidomain.entities._ - -object trial { - import DefaultJsonProtocol._ - import Trial._ - import common._ - - implicit val trialStatusFormat: RootJsonFormat[Status] = new EnumJsonFormat[Status]( - "New" -> Status.New, - "ReviewSummary" -> Status.ReviewSummary, - "Summarized" -> Status.Summarized, - "PendingUpdate" -> Status.PendingUpdate, - "Update" -> Status.Update, - "ReviewCriteria" -> Status.ReviewCriteria, - "Done" -> Status.Done, - "Flagged" -> Status.Flagged, - "Archived" -> Status.Archived - ) - - implicit val trialFormat: RootJsonFormat[Trial] = new RootJsonFormat[Trial] { - override def write(obj: Trial) = - JsObject( - "id" -> obj.id.toJson, - "externalid" -> obj.externalId.toJson, - "lastUpdate" -> ZonedDateTime.of(obj.lastUpdate, ZoneId.of("Z")).toJson, - "status" -> obj.status.toJson, - "assignee" -> obj.assignee.toJson, - "previousStatus" -> obj.previousStatus.toJson, - "previousAssignee" -> obj.previousAssignee.toJson, - "lastActiveUser" -> obj.lastActiveUserId.toJson, - "phase" -> obj.phase.toJson, - "hypothesisId" -> obj.hypothesisId.toJson, - "studyDesignId" -> obj.studyDesignId.toJson, - "originalStudyDesignId" -> obj.originalStudyDesign.toJson, - "isPartner" -> obj.isPartner.toJson, - "overview" -> obj.overview.toJson, - "overviewTemplate" -> obj.overviewTemplate.toJson, - "isUpdated" -> obj.isUpdated.toJson, - "title" -> obj.title.toJson, - "originalTitle" -> obj.originalTitle.toJson - ) - - override def read(json: JsValue): Trial = { - json match { - case JsObject(fields) => - val id = fields - .get("id") - .map(_.convertTo[StringId[Trial]]) - .getOrElse(deserializationError(s"Trial create json object does not contain `id` field: $json")) - val externalid = fields - .get("externalid") - .map(_.convertTo[UuidId[Trial]]) - .getOrElse(deserializationError(s"Trial create json object does not contain `externalid` field: $json")) - val status = fields - .get("status") - .map(_.convertTo[Trial.Status]) - .getOrElse(deserializationError(s"Trial create json object does not contain `status` field: $json")) - val assignee = fields - .get("assignee") - .flatMap(_.convertTo[Option[xyz.driver.core.Id[User]]]) - val previousStatus = fields - .get("previousStatus") - .flatMap(_.convertTo[Option[Trial.Status]]) - val previousAssignee = fields - .get("previousAssignee") - .flatMap(_.convertTo[Option[xyz.driver.core.Id[User]]]) - val lastActiveUser = fields - .get("lastActiveUser") - .flatMap(_.convertTo[Option[xyz.driver.core.Id[User]]]) - val lastUpdate = fields - .get("lastUpdate") - .map(_.convertTo[LocalDateTime]) - .getOrElse(deserializationError(s"Trial create json object does not contain `lastUpdate` field: $json")) - val phase = fields - .get("phase") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"Trial create json object does not contain `phase` field: $json")) - val hypothesisId = fields - .get("hypothesisId") - .flatMap(_.convertTo[Option[UuidId[Hypothesis]]]) - val studyDesignId = fields - .get("studyDesignId") - .flatMap(_.convertTo[Option[LongId[StudyDesign]]]) - val originalStudyDesignId = fields - .get("originalStudyDesignId") - .flatMap(_.convertTo[Option[String]]) - val isPartner = fields - .get("isPartner") - .map(_.convertTo[Boolean]) - .getOrElse(deserializationError(s"Trial create json object does not contain `isPartner` field: $json")) - val overview = fields - .get("overview") - .flatMap(_.convertTo[Option[String]]) - val overviewTemplate = fields - .get("overviewTemplate") - .map(_.convertTo[String]) - .getOrElse( - deserializationError(s"Trial create json object does not contain `overviewTemplate` field: $json")) - val isUpdated = fields - .get("isUpdated") - .map(_.convertTo[Boolean]) - .getOrElse(deserializationError(s"Trial create json object does not contain `isUpdated` field: $json")) - val title = fields - .get("title") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"Trial create json object does not contain `title` field: $json")) - val originalTitle = fields - .get("originalTitle") - .map(_.convertTo[String]) - .getOrElse(deserializationError(s"Trial create json object does not contain `originalTitle` field: $json")) - - Trial( - id, - externalid, - status, - assignee, - previousStatus, - previousAssignee, - lastActiveUser, - lastUpdate, - phase, - hypothesisId, - studyDesignId, - originalStudyDesignId, - isPartner, - overview, - overviewTemplate, - isUpdated, - title, - originalTitle - ) - - case _ => deserializationError(s"Expected Json Object as Trial, but got $json") - } - } - } - - def applyUpdateToTrial(json: JsValue, orig: Trial): Trial = json match { - case JsObject(fields) => - val hypothesisId = fields - .get("hypothesisId") - .map(_.convertTo[Option[UuidId[Hypothesis]]]) - .getOrElse(orig.hypothesisId) - - val studyDesignId = fields - .get("studyDesignId") - .map(_.convertTo[Option[LongId[StudyDesign]]]) - .getOrElse(orig.studyDesignId) - - val overview = fields - .get("overview") - .map(_.convertTo[Option[String]]) - .getOrElse(orig.overview) - - val title = fields - .get("title") - .map(_.convertTo[Option[String]].getOrElse("")) - .getOrElse(orig.title) - - val originalTitle = fields - .get("originalTitle") - .flatMap(_.convertTo[Option[String]]) - .getOrElse(orig.originalTitle) - - orig.copy( - hypothesisId = hypothesisId, - studyDesignId = studyDesignId, - overview = overview, - title = title, - originalTitle = originalTitle - ) - - case _ => deserializationError(s"Expected Json Object as Trial, but got $json") - } - - implicit val trialCreationRequestFormat: RootJsonFormat[TrialCreationRequest] = - jsonFormat3(TrialCreationRequest.apply) - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trialhistory.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/trialhistory.scala deleted file mode 100644 index f71ec12..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trialhistory.scala +++ /dev/null @@ -1,32 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import xyz.driver.core.json._ -import xyz.driver.pdsuidomain.entities._ - -object trialhistory { - import DefaultJsonProtocol._ - import TrialHistory._ - import common._ - - implicit val trialStateFormat = new EnumJsonFormat[State]( - "Summarize" -> State.Summarize, - "Criteriarize" -> State.Criteriarize, - "Review" -> State.Review, - "ReviewSummary" -> State.ReviewSummary, - "ReviewCriteria" -> State.ReviewCriteria, - "Flag" -> State.Flag - ) - - implicit val trialActionFormat = new EnumJsonFormat[Action]( - "Start" -> Action.Start, - "Submit" -> Action.Submit, - "Unassign" -> Action.Unassign, - "Resolve" -> Action.Resolve, - "Flag" -> Action.Flag, - "Archive" -> Action.Archive - ) - - implicit val trialHistoryFormat: RootJsonFormat[TrialHistory] = jsonFormat7(TrialHistory.apply) - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trialissue.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/trialissue.scala deleted file mode 100644 index 79882c2..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trialissue.scala +++ /dev/null @@ -1,134 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json.{RootJsonReader, _} -import xyz.driver.core.{Id, auth} -import xyz.driver.core.auth.User -import xyz.driver.core.json._ -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities._ - -object trialissue { - - import DefaultJsonProtocol._ - import common._ - - private def deserializationErrorFieldMessage(field: String, json: JsValue)(implicit className: String) = { - deserializationError(s"$className json object do not contain '$field' field: $json") - } - - private def deserializationErrorEntityMessage(json: JsValue)(implicit className: String) = { - deserializationError(s"Expected Json Object as $className, but got $json") - } - - def applyUpdateToTrialIssue(json: JsValue, orig: TrialIssue): TrialIssue = { - json.asJsObject.getFields("text", "evidence", "archiveRequired", "meta") match { - case Seq(text, evidence, archiveRequired, meta) => - orig.copy( - text = text.convertTo[String], - evidence = evidence.convertTo[String], - archiveRequired = archiveRequired.convertTo[Boolean], - meta = meta.convertTo[String] - ) - - case _ => deserializationError(s"Expected Json Object as partial TrialIssue, but got $json") - } - } - - def jsValueToTrialIssue(json: JsValue, trialId: StringId[Trial], userId: xyz.driver.core.Id[User]): TrialIssue = { - json.asJsObject.getFields("text", "evidence", "meta") match { - case Seq(text, evidence, meta) => - TrialIssue( - id = json.asJsObject.fields.get("id").flatMap(_.convertTo[Option[LongId[TrialIssue]]]).getOrElse(LongId(0)), - userId = userId, - trialId = trialId, - lastUpdate = LocalDateTime.MIN, - isDraft = true, - text = text.convertTo[String], - evidence = evidence.convertTo[String], - archiveRequired = false, - meta = meta.convertTo[String] - ) - - case _ => deserializationError(s"Expected Json Object as TrialIssue, but got $json") - } - - } - - implicit val trialIssueWriter = new RootJsonWriter[TrialIssue] { - override def write(obj: TrialIssue) = JsObject( - "id" -> obj.id.toJson, - "text" -> obj.text.toJson, - "lastUpdate" -> obj.lastUpdate.toJson, - "userId" -> obj.userId.toJson, - "isDraft" -> obj.isDraft.toJson, - "evidence" -> obj.evidence.toJson, - "archiveRequired" -> obj.archiveRequired.toJson, - "meta" -> obj.meta.toJson - ) - } - - def trialIssueReader(trialId: StringId[Trial]): RootJsonReader[TrialIssue] = - new RootJsonReader[TrialIssue] { - implicit val className: String = "TrialIssue" - - override def read(json: JsValue): TrialIssue = json match { - case JsObject(fields) => - val id = fields - .get("id") - .map(_.convertTo[LongId[TrialIssue]]) - .getOrElse(deserializationErrorFieldMessage("id", json)) - - val text = fields - .get("text") - .map(_.convertTo[String]) - .getOrElse(deserializationErrorFieldMessage("text", json)) - - val lastUpdate = fields - .get("lastUpdate") - .map(_.convertTo[LocalDateTime]) - .getOrElse(deserializationErrorFieldMessage("lastUpdate", json)) - - val userId = fields - .get("userId") - .map(_.convertTo[Id[auth.User]]) - .getOrElse(deserializationErrorFieldMessage("userId", json)) - - val isDraft = fields - .get("isDraft") - .map(_.convertTo[Boolean]) - .getOrElse(deserializationErrorFieldMessage("isDraft", json)) - - val evidence = fields - .get("evidence") - .map(_.convertTo[String]) - .getOrElse(deserializationErrorFieldMessage("evidence", json)) - - val archiveRequired = fields - .get("archiveRequired") - .map(_.convertTo[Boolean]) - .getOrElse(deserializationErrorFieldMessage("archiveRequired", json)) - - val meta = fields - .get("meta") - .map(_.convertTo[String]) - .getOrElse(deserializationErrorFieldMessage("meta", json)) - - TrialIssue( - id = id, - userId = userId, - trialId = trialId, - lastUpdate = lastUpdate, - isDraft = isDraft, - text = text, - evidence = evidence, - archiveRequired = archiveRequired, - meta = meta - ) - - case _ => deserializationErrorEntityMessage(json) - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala deleted file mode 100644 index d4ff62b..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala +++ /dev/null @@ -1,130 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.Arm - -import scala.concurrent.Future - -object ArmService { - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - trait DefaultNotFoundError { - def userMessage: String = "Arm not found" - } - - sealed trait GetByIdReply - object GetByIdReply { - - final case class Entity(x: Arm) extends GetByIdReply - - type Error = GetByIdReply with DomainError - - case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - - final case class CommonError(userMessage: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]) - extends GetByIdReply with DomainError - } - - sealed trait GetListReply - object GetListReply { - type Error = GetListReply with DomainError - - final case class EntityList(xs: Seq[Arm], totalFound: Int) extends GetListReply - - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait UpdateReply - object UpdateReply { - - final case class Updated(updated: Arm) extends UpdateReply - - type Error = UpdateReply with DomainError - - case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - - final case class AlreadyExistsError(x: Arm) extends UpdateReply with DomainError { - val userMessage = s"The arm with such name of trial already exists." - } - - implicit def toPhiString(reply: UpdateReply): PhiString = reply match { - case Updated(x) => phi"Updated($x)" - case x: Error => DomainError.toPhiString(x) - } - } - - sealed trait CreateReply - object CreateReply { - final case class Created(x: Arm) extends CreateReply - - type Error = CreateReply with DomainError - - case object AuthorizationError - extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends CreateReply with DomainError - - final case class AlreadyExistsError(x: Arm) extends CreateReply with DomainError { - val userMessage = s"The arm with this name of trial already exists." - } - - implicit def toPhiString(reply: CreateReply): PhiString = reply match { - case Created(x) => phi"Created($x)" - case x: Error => DomainError.toPhiString(x) - } - } - - sealed trait DeleteReply - object DeleteReply { - case object Deleted extends DeleteReply - - type Error = DeleteReply with DomainError - - case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends DeleteReply with DomainError - } -} - -trait ArmService { - - import ArmService._ - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def getById(armId: LongId[Arm])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def create(draftArm: Arm)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def update(origArm: Arm, draftArm: Arm)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def delete(id: LongId[Arm])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala deleted file mode 100644 index 9c6341c..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala +++ /dev/null @@ -1,126 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import java.time.LocalDateTime - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities._ - -import scala.concurrent.Future - -object CriterionService { - - trait DefaultNotFoundError { - def userMessage: String = "Criterion not found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - final case class RichCriterion(criterion: Criterion, - armIds: Seq[LongId[EligibilityArm]], - labels: Seq[CriterionLabel]) - object RichCriterion { - implicit def toPhiString(x: RichCriterion): PhiString = { - import x._ - phi"RichCriterion(criterion=$criterion, armIds=$armIds, labels=$labels)" - } - } - - sealed trait CreateReply - object CreateReply { - type Error = CreateReply with DomainError - - final case class Created(x: RichCriterion) extends CreateReply - - case object AuthorizationError - extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - - final case class CommonError(userMessage: String) extends CreateReply with DomainError - } - - sealed trait GetByIdReply - object GetByIdReply { - final case class Entity(x: RichCriterion) extends GetByIdReply - - type Error = GetByIdReply with DomainError - - case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - - final case class CommonError(userMessage: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]) - extends GetByIdReply with DomainError - - implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { - case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x) => phi"GetByIdReply.Entity($x)" - } - } - - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[RichCriterion], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListReply - - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait UpdateReply - object UpdateReply { - type Error = UpdateReply with DomainError - - final case class Updated(updated: RichCriterion) extends UpdateReply - - case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - } - - sealed trait DeleteReply - object DeleteReply { - case object Deleted extends DeleteReply - - type Error = DeleteReply with DomainError - - case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends DeleteReply with DomainError - } -} - -trait CriterionService { - - import CriterionService._ - - def create(draftRichCriterion: RichCriterion)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def getById(id: LongId[Criterion])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def update(origRichCriterion: RichCriterion, draftRichCriterion: RichCriterion)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def delete(id: LongId[Criterion])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentHistoryService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentHistoryService.scala deleted file mode 100644 index d209b39..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentHistoryService.scala +++ /dev/null @@ -1,45 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import java.time.LocalDateTime - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuidomain.entities.{Document, DocumentHistory} - -import scala.concurrent.Future - -object DocumentHistoryService { - - trait DefaultNotFoundError { - def userMessage: String = "Document history not found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[DocumentHistory], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListReply - - final case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - -} - -trait DocumentHistoryService { - - import DocumentHistoryService._ - - def getListByDocumentId(id: LongId[Document], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentIssueService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentIssueService.scala deleted file mode 100644 index f7fc7b2..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentIssueService.scala +++ /dev/null @@ -1,95 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import java.time.LocalDateTime - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuidomain.entities.{Document, DocumentIssue} - -import scala.concurrent.Future - -object DocumentIssueService { - - trait DefaultNotFoundError { - def userMessage: String = "DocumentIssue not found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait CreateReply - object CreateReply { - type Error = CreateReply with DomainError - final case class Created(x: DocumentIssue) extends CreateReply - case object AuthorizationError - extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - final case class CommonError(userMessage: String) extends CreateReply with DomainError - } - - sealed trait GetByIdReply - object GetByIdReply { - type Error = GetByIdReply with DomainError - final case class Entity(x: DocumentIssue) extends GetByIdReply - case object NotFoundError extends GetByIdReply with DomainError.NotFoundError with DefaultNotFoundError - final case class CommonError(userMessage: String) extends GetByIdReply with DomainError - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait GetListByDocumentIdReply - object GetListByDocumentIdReply { - type Error = GetListByDocumentIdReply with DomainError - final case class EntityList(xs: Seq[DocumentIssue], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListByDocumentIdReply - case object NotFoundError extends GetListByDocumentIdReply with DomainError.NotFoundError with DefaultNotFoundError - case object AuthorizationError - extends GetListByDocumentIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait UpdateReply - object UpdateReply { - type Error = UpdateReply with DomainError - final case class Updated(updated: DocumentIssue) extends UpdateReply - case object AuthorizationError - extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - } - - sealed trait DeleteReply - object DeleteReply { - type Error = DeleteReply with DomainError - case object Deleted extends DeleteReply - case object AuthorizationError - extends DeleteReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case object NotFoundError extends DeleteReply with DomainError.NotFoundError with DefaultNotFoundError - final case class CommonError(userMessage: String) extends DeleteReply with DomainError - } -} - -trait DocumentIssueService { - - import DocumentIssueService._ - - def create(draft: DocumentIssue)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def getById(documentId: LongId[Document], id: LongId[DocumentIssue])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def getListByDocumentId(documentId: LongId[Document], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListByDocumentIdReply] - - def update(orig: DocumentIssue, draft: DocumentIssue)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def delete(documentId: LongId[Document], id: LongId[DocumentIssue])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala deleted file mode 100644 index a16ac9c..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala +++ /dev/null @@ -1,147 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import java.time.LocalDateTime - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities._ - -import scala.concurrent.Future - -object DocumentService { - - trait DefaultNotFoundError { - def userMessage: String = "Can not find the document" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait GetByIdReply - object GetByIdReply { - final case class Entity(x: Document) extends GetByIdReply - - type Error = GetByIdReply with DomainError - - case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - - final case class CommonError(userMessage: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]) - extends GetByIdReply with DomainError - - implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { - case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x) => phi"GetByIdReply.Entity($x)" - } - } - - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[Document], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListReply - - type Error = GetListReply with DomainError - - case object AuthorizationError - extends GetListReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends GetListReply with DomainError - } - - sealed trait CreateReply - object CreateReply { - final case class Created(x: Document) extends CreateReply - - type Error = CreateReply with DomainError - - case object NotFoundError extends CreateReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends CreateReply with DomainError - } - - sealed trait UpdateReply - object UpdateReply { - final case class Updated(updated: Document) extends UpdateReply - - type Error = UpdateReply with DomainError - - case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - - implicit def toPhiString(reply: UpdateReply): PhiString = reply match { - case Updated(x) => phi"Updated($x)" - case x: Error => DomainError.toPhiString(x) - } - } - - sealed trait DeleteReply - object DeleteReply { - case object Deleted extends DeleteReply - - type Error = DeleteReply with DomainError - - case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends DeleteReply with DomainError - } -} - -trait DocumentService { - - import DocumentService._ - - def getById(id: LongId[Document])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def create(draftDocument: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def update(orig: Document, draft: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def delete(id: LongId[Document])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] - - def start(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def submit(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def restart(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def flag(orig: Document)(implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def resolve(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def unassign(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def archive(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala deleted file mode 100644 index ccaed22..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala +++ /dev/null @@ -1,26 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.Sorting -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuidomain.entities.DocumentType -import xyz.driver.pdsuidomain.services.DocumentTypeService.GetListReply - -import scala.concurrent.Future - -object DocumentTypeService { - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[DocumentType], totalFound: Int) extends GetListReply - case object AuthorizationError extends GetListReply with DomainError.AuthorizationError { - def userMessage: String = "Access denied" - } - } -} - -trait DocumentTypeService { - - def getAll(sorting: Option[Sorting] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityArmService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityArmService.scala deleted file mode 100644 index 8e67627..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityArmService.scala +++ /dev/null @@ -1,145 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.{EligibilityArm, EligibilityArmWithDiseases, SlotArm} - -import scala.concurrent.Future - -object EligibilityArmService { - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - trait DefaultNotFoundError { - def userMessage: String = "EligibilityArm not found" - } - - trait SlotArmNotFoundError { - def userMessage: String = "SlotArm not found" - } - - sealed trait GetByIdReply - object GetByIdReply { - - final case class Entity(x: EligibilityArmWithDiseases) extends GetByIdReply - - type Error = GetByIdReply with DomainError - - case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - - final case class CommonError(userMessage: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]) - extends GetByIdReply with DomainError - } - - sealed trait GetListReply - object GetListReply { - type Error = GetListReply with DomainError - - final case class EntityList(xs: Seq[EligibilityArmWithDiseases], totalFound: Int) extends GetListReply - - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait UpdateReply - object UpdateReply { - - final case class Updated(updated: EligibilityArmWithDiseases) extends UpdateReply - - type Error = UpdateReply with DomainError - - case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - - final case class AlreadyExistsError(x: EligibilityArmWithDiseases) extends UpdateReply with DomainError { - val userMessage = s"The arm with such name of trial already exists." - } - - implicit def toPhiString(reply: UpdateReply): PhiString = reply match { - case Updated(x) => phi"Updated($x)" - case x: Error => DomainError.toPhiString(x) - } - } - - sealed trait CreateReply - object CreateReply { - final case class Created(x: EligibilityArmWithDiseases) extends CreateReply - - type Error = CreateReply with DomainError - - case object AuthorizationError - extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - case object NotFoundError extends CreateReply with SlotArmNotFoundError with DomainError.NotFoundError - - final case class CommonError(userMessage: String) extends CreateReply with DomainError - - final case class AlreadyExistsError(x: EligibilityArmWithDiseases) extends CreateReply with DomainError { - val userMessage = s"The arm with this name of trial already exists." - } - - implicit def toPhiString(reply: CreateReply): PhiString = reply match { - case Created(x) => phi"Created($x)" - case x: Error => DomainError.toPhiString(x) - } - } - - sealed trait DeleteReply - object DeleteReply { - case object Deleted extends DeleteReply - - type Error = DeleteReply with DomainError - - case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends DeleteReply with DomainError - } -} - -trait EligibilityArmService { - - import EligibilityArmService._ - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def getByEligibilityId(armId: LongId[EligibilityArm])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def deleteByEligibilityIdSlotArmId(armId: LongId[EligibilityArm], slotArmId: LongId[SlotArm])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] - - def getBySlotId(armId: LongId[SlotArm], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def create(slotArmId: LongId[SlotArm], draftEligibilityArm: EligibilityArmWithDiseases)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def update(origEligibilityArm: EligibilityArmWithDiseases, draftEligibilityArm: EligibilityArmWithDiseases)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def delete(id: LongId[EligibilityArm])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/EligibilitySnapshotService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/EligibilitySnapshotService.scala deleted file mode 100644 index b3e6673..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/EligibilitySnapshotService.scala +++ /dev/null @@ -1,16 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuidomain.entities.{Patient => PdsuiPatient} -import xyz.driver.pdsuidomain.entities.eligibility.EligibleTrial - -import scala.concurrent.Future - -trait EligibilitySnapshotService { - - def eligibilitySnapshot(patientId: UuidId[PdsuiPatient])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Seq[EligibleTrial]] - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityVerificationService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityVerificationService.scala deleted file mode 100644 index 3788617..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityVerificationService.scala +++ /dev/null @@ -1,22 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.Id -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.patient.{CancerType, Patient} -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities.eligibility.{MatchedPatient, MismatchRankedLabels} -import xyz.driver.pdsuidomain.entities.EligibilityArm - -import scala.concurrent.Future -import scalaz.ListT - -trait EligibilityVerificationService { - - def getMatchedPatients()(implicit ctx: AuthorizedServiceRequestContext[AuthUserInfo]): ListT[Future, MatchedPatient] - - def getMismatchRankedLabels(patientId: Id[Patient], - cancerType: CancerType, - excludedArms: Seq[LongId[EligibilityArm]])( - implicit ctx: AuthorizedServiceRequestContext[AuthUserInfo]): Future[MismatchRankedLabels] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala deleted file mode 100644 index fbfb1d2..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala +++ /dev/null @@ -1,126 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.entities.export.patient.ExportPatientWithLabels - -import scala.concurrent.Future - -object ExtractedDataService { - - trait DefaultNotFoundError { - def userMessage: String = "Extracted data hasn't been found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - final case class RichExtractedData(extractedData: ExtractedData, labels: List[ExtractedDataLabel]) - - object RichExtractedData { - implicit def toPhiString(x: RichExtractedData): PhiString = { - import x._ - phi"RichExtractedData(extractedData=$extractedData, labels=$labels)" - } - } - - sealed trait GetByIdReply - object GetByIdReply { - type Error = GetByIdReply with DomainError - final case class Entity(x: RichExtractedData) extends GetByIdReply - - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - - case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError - - final case class CommonError(userMessage: String) extends GetByIdReply with DomainError - } - - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[RichExtractedData], totalFound: Int) extends GetListReply - - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait GetPatientLabelsReply - object GetPatientLabelsReply { - type Error = GetPatientLabelsReply with DomainError - - final case class Entity(x: ExportPatientWithLabels) extends GetPatientLabelsReply - - case object NotFoundError extends GetPatientLabelsReply with DomainError.NotFoundError { - def userMessage: String = "Patient not found" - } - } - - sealed trait CreateReply - object CreateReply { - type Error = CreateReply with DomainError - final case class Created(x: RichExtractedData) extends CreateReply - - case object AuthorizationError - extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - - final case class CommonError(userMessage: String) extends CreateReply with DomainError - } - - sealed trait UpdateReply - object UpdateReply { - type Error = UpdateReply with DomainError - final case class Updated(updated: RichExtractedData) extends UpdateReply - - case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError - - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - } - - sealed trait DeleteReply - object DeleteReply { - type Error = DeleteReply with DomainError - case object Deleted extends DeleteReply - - case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError - - final case class CommonError(userMessage: String) extends DeleteReply with DomainError - } -} - -trait ExtractedDataService { - - import ExtractedDataService._ - - def getById(id: LongId[ExtractedData])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def getPatientLabels(id: UuidId[Patient])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetPatientLabelsReply] - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def create(draftRichExtractedData: RichExtractedData)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def update(origRichExtractedData: RichExtractedData, draftRichExtractedData: RichExtractedData)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def delete(id: LongId[ExtractedData])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala deleted file mode 100644 index 929dd58..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala +++ /dev/null @@ -1,69 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.Sorting -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuidomain.entities.Hypothesis - -import scala.concurrent.Future - -object HypothesisService { - trait DefaultNotFoundError { - def userMessage: String = "Hypothesis not found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[Hypothesis], totalFound: Int) extends GetListReply - - case object AuthorizationError extends GetListReply with DomainError.AuthorizationError { - def userMessage: String = "Access denied" - } - } - - sealed trait CreateReply - object CreateReply { - final case class Created(x: Hypothesis) extends CreateReply - - type Error = CreateReply with DomainError - - case object AuthorizationError - extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends CreateReply with DomainError - } - - sealed trait DeleteReply - object DeleteReply { - case object Deleted extends DeleteReply - - type Error = DeleteReply with DomainError - - case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends DeleteReply with DomainError - } -} - -trait HypothesisService { - - import HypothesisService._ - - def getAll(sorting: Option[Sorting] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def create(draftHypothesis: Hypothesis)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def delete(id: UuidId[Hypothesis])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala deleted file mode 100644 index 85e557a..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala +++ /dev/null @@ -1,119 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities._ - -import scala.concurrent.Future - -object InterventionService { - - trait DefaultNotFoundError { - def userMessage: String = "Intervention not found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[InterventionWithArms], totalFound: Int) extends GetListReply - - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait GetByIdReply - object GetByIdReply { - final case class Entity(x: InterventionWithArms) extends GetByIdReply - - type Error = GetByIdReply with DomainError - - case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - - final case class CommonError(userMessage: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]) - extends GetByIdReply with DomainError - - implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { - case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x) => phi"GetByIdReply.Entity($x)" - } - } - - sealed trait UpdateReply - object UpdateReply { - type Error = UpdateReply with DomainError - - final case class Updated(updated: InterventionWithArms) extends UpdateReply - - case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - } - - sealed trait CreateReply - object CreateReply { - final case class Created(x: InterventionWithArms) extends CreateReply - - type Error = CreateReply with DomainError - - case object AuthorizationError - extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends CreateReply with DomainError - - implicit def toPhiString(reply: CreateReply): PhiString = reply match { - case Created(x) => phi"Created($x)" - case x: Error => DomainError.toPhiString(x) - } - } - - sealed trait DeleteReply - object DeleteReply { - case object Deleted extends DeleteReply - - type Error = DeleteReply with DomainError - - case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends DeleteReply with DomainError - } - -} - -trait InterventionService { - - import InterventionService._ - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def getById(id: LongId[Intervention])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def update(origIntervention: InterventionWithArms, draftIntervention: InterventionWithArms)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def create(draftIntervention: InterventionWithArms)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def delete(id: LongId[Intervention])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala deleted file mode 100644 index 58f336d..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala +++ /dev/null @@ -1,28 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.Sorting -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuidomain.entities.InterventionType - -import scala.concurrent.Future - -object InterventionTypeService { - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[InterventionType], totalFound: Int) extends GetListReply - - case object AuthorizationError extends GetListReply with DomainError.AuthorizationError { - def userMessage: String = "Access denied" - } - } -} - -trait InterventionTypeService { - - import InterventionTypeService._ - - def getAll(sorting: Option[Sorting] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordHistoryService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordHistoryService.scala deleted file mode 100644 index 42285b1..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordHistoryService.scala +++ /dev/null @@ -1,45 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import java.time.LocalDateTime - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuidomain.entities.{MedicalRecord, MedicalRecordHistory} - -import scala.concurrent.Future - -object MedicalRecordHistoryService { - - trait DefaultNotFoundError { - def userMessage: String = "Medical record history not found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[MedicalRecordHistory], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListReply - - final case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - -} - -trait MedicalRecordHistoryService { - - import MedicalRecordHistoryService._ - - def getListByRecordId(id: LongId[MedicalRecord], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordIssueService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordIssueService.scala deleted file mode 100644 index dc10a93..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordIssueService.scala +++ /dev/null @@ -1,95 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import java.time.LocalDateTime - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuidomain.entities.{MedicalRecord, MedicalRecordIssue} - -import scala.concurrent.Future - -object MedicalRecordIssueService { - - trait DefaultNotFoundError { - def userMessage: String = "MedicalRecordIssue not found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait CreateReply - object CreateReply { - type Error = CreateReply with DomainError - final case class Created(x: MedicalRecordIssue) extends CreateReply - case object AuthorizationError - extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - final case class CommonError(userMessage: String) extends CreateReply with DomainError - } - - sealed trait GetByIdReply - object GetByIdReply { - type Error = GetByIdReply with DomainError - final case class Entity(x: MedicalRecordIssue) extends GetByIdReply - case object NotFoundError extends GetByIdReply with DomainError.NotFoundError with DefaultNotFoundError - final case class CommonError(userMessage: String) extends GetByIdReply with DomainError - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait GetListByRecordIdReply - object GetListByRecordIdReply { - type Error = GetListByRecordIdReply with DomainError - final case class EntityList(xs: Seq[MedicalRecordIssue], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListByRecordIdReply - case object NotFoundError extends GetListByRecordIdReply with DomainError.NotFoundError with DefaultNotFoundError - case object AuthorizationError - extends GetListByRecordIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait UpdateReply - object UpdateReply { - type Error = UpdateReply with DomainError - final case class Updated(updated: MedicalRecordIssue) extends UpdateReply - case object AuthorizationError - extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - } - - sealed trait DeleteReply - object DeleteReply { - type Error = DeleteReply with DomainError - case object Deleted extends DeleteReply - case object AuthorizationError - extends DeleteReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case object NotFoundError extends DeleteReply with DomainError.NotFoundError with DefaultNotFoundError - final case class CommonError(userMessage: String) extends DeleteReply with DomainError - } -} - -trait MedicalRecordIssueService { - - import MedicalRecordIssueService._ - - def create(draft: MedicalRecordIssue)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def getById(recordId: LongId[MedicalRecord], id: LongId[MedicalRecordIssue])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def getListByRecordId(recordId: LongId[MedicalRecord], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListByRecordIdReply] - - def update(orig: MedicalRecordIssue, draft: MedicalRecordIssue)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def delete(recordId: LongId[MedicalRecord], id: LongId[MedicalRecordIssue])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala deleted file mode 100644 index 0d2c58b..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala +++ /dev/null @@ -1,126 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import akka.NotUsed -import akka.stream.scaladsl.Source -import akka.util.ByteString -import java.time.LocalDateTime - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.error._ -import xyz.driver.pdsuidomain.entities.MedicalRecord.PdfSource -import xyz.driver.pdsuidomain.entities._ - -import scala.concurrent.Future - -object MedicalRecordService { - - type PdfSourceFetcher = (String, String) => Future[PdfSource] - - trait DefaultNotFoundError { - def userMessage: String = "Medical record hasn't been found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait GetByIdReply - object GetByIdReply { - final case class Entity(x: MedicalRecord) extends GetByIdReply - - type Error = GetByIdReply with DomainError - - case object NotFoundError extends GetByIdReply with DomainError.NotFoundError with DefaultNotFoundError - - final case class CommonError(userMessage: String) extends GetByIdReply with DomainError - - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[MedicalRecord], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListReply - - type Error = GetListReply with DomainError - - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - - case object NotFoundError extends GetListReply with DomainError.NotFoundError { - def userMessage: String = "Patient wasn't found" - } - } - - sealed trait CreateReply - object CreateReply { - type Error = CreateReply with DomainError - - final case class Created(x: MedicalRecord) extends CreateReply - - final case class CommonError(userMessage: String) extends CreateReply with DomainError - } - - sealed trait UpdateReply - object UpdateReply { - type Error = UpdateReply with DomainError - - final case class Updated(updated: MedicalRecord) extends UpdateReply - - case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - } - - final case class Settings(pdfSourceBucket: String) -} - -trait MedicalRecordService { - - import MedicalRecordService._ - - def getById(recordId: LongId[MedicalRecord])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def getPdfSource(recordId: LongId[MedicalRecord])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Source[ByteString, NotUsed]] - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def create(draft: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def update(origRecord: MedicalRecord, draftRecord: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def start(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def submit(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def restart(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def flag(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def resolve(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def unassign(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def archive(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala deleted file mode 100644 index 915dc20..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala +++ /dev/null @@ -1,28 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ - -import scala.concurrent.Future - -trait PatientCriterionService { - - def getAll(patientId: UuidId[Patient], - origFilter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[RichPatientCriterion]] - - def getById(patientId: UuidId[Patient], id: LongId[PatientCriterion])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Option[RichPatientCriterion]] - - def updateList(patientId: UuidId[Patient], draftEntities: List[DraftPatientCriterion])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Unit] - - def update(origEntity: PatientCriterion, draftEntity: PatientCriterion, patientId: UuidId[Patient])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[RichPatientCriterion] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala deleted file mode 100644 index e73d537..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala +++ /dev/null @@ -1,29 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ - -import scala.concurrent.Future - -trait PatientEligibleTrialService { - - def getAll(patientId: UuidId[Patient], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[RichPatientEligibleTrial]] - - def getById(patientId: UuidId[Patient], id: LongId[PatientTrialArmGroup])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Option[RichPatientEligibleTrial]] - - def getCriterionListByGroupId(patientId: UuidId[Patient], id: LongId[PatientTrialArmGroup])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[RichPatientCriterion]] - - def update(origEligibleTrialWithTrial: RichPatientEligibleTrial, draftPatientTrialArmGroup: PatientTrialArmGroupView)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[RichPatientEligibleTrial] - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientHistoryService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientHistoryService.scala deleted file mode 100644 index 3f44e58..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientHistoryService.scala +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities.{Patient, PatientHistory} - -import scala.concurrent.Future - -trait PatientHistoryService { - - def getListByPatientId(id: UuidId[Patient], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[PatientHistory]] - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala deleted file mode 100644 index 0191b5a..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala +++ /dev/null @@ -1,25 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities.{Hypothesis, Patient, PatientHypothesis} - -import scala.concurrent.Future - -trait PatientHypothesisService { - - def getAll(patientId: UuidId[Patient], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[PatientHypothesis]] - - def getById(patientId: UuidId[Patient], hypothesisId: UuidId[Hypothesis])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Option[PatientHypothesis]] - - def update(origPatientHypothesis: PatientHypothesis, draftPatientHypothesis: PatientHypothesis)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[PatientHypothesis] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientIssueService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientIssueService.scala deleted file mode 100644 index b2ba357..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientIssueService.scala +++ /dev/null @@ -1,32 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities.{Patient, PatientIssue} - -import scala.concurrent.Future - -trait PatientIssueService { - - def create(draft: PatientIssue)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[PatientIssue] - - def getById(patientId: UuidId[Patient], id: LongId[PatientIssue])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Option[PatientIssue]] - - def getListByPatientId(patientId: UuidId[Patient], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[PatientIssue]] - - def update(orig: PatientIssue, draft: PatientIssue)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[PatientIssue] - - def delete(patientId: UuidId[Patient], id: LongId[PatientIssue])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Unit] - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala deleted file mode 100644 index a999bf9..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala +++ /dev/null @@ -1,24 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.labels.Label -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ - -import scala.concurrent.Future - -trait PatientLabelEvidenceService { - - def getById(patientId: UuidId[Patient], labelId: LongId[Label], id: LongId[PatientLabelEvidence])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Option[PatientLabelEvidenceView]] - - def getAll(patientId: UuidId[Patient], - labelId: LongId[Label], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[PatientLabelEvidenceView]] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala deleted file mode 100644 index 0eeac53..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala +++ /dev/null @@ -1,31 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.labels.Label -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ - -import scala.concurrent.Future - -trait PatientLabelService { - - def getAll(patientId: UuidId[Patient], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[RichPatientLabel]] - - def getDefiningCriteriaList(patientId: UuidId[Patient], - hypothesisId: UuidId[Hypothesis], - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[PatientLabel]] - - def getByLabelIdOfPatient(patientId: UuidId[Patient], labelId: LongId[Label])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Option[RichPatientLabel]] - - def update(origPatientLabel: PatientLabel, draftPatientLabel: PatientLabel)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[RichPatientLabel] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala deleted file mode 100644 index 6f95fdb..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala +++ /dev/null @@ -1,39 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ - -import scala.concurrent.Future - -trait PatientService { - - def getById(id: UuidId[Patient])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Option[Patient]] - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[Patient]] - - def unassign(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] - - def start(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] - - def submit(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] - - def restart(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] - - def flag(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] - - def resolve(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala deleted file mode 100644 index ab936d6..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala +++ /dev/null @@ -1,27 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.Sorting -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuidomain.entities.ProviderType - -import scala.concurrent.Future - -object ProviderTypeService { - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[ProviderType], totalFound: Int) extends GetListReply - case object AuthorizationError extends GetListReply with DomainError.AuthorizationError { - def userMessage: String = "Access denied" - } - } -} - -trait ProviderTypeService { - - import ProviderTypeService._ - - def getAll(sorting: Option[Sorting] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/QueueUploadService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/QueueUploadService.scala deleted file mode 100644 index 6cb2051..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/QueueUploadService.scala +++ /dev/null @@ -1,80 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.error.DomainError - -import scala.concurrent.Future - -object QueueUploadService { - trait DefaultNotFoundError { - def userMessage: String = "Message not found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait CreateReply - object CreateReply { - type Error = CreateReply with DomainError - - final case class Created(x: BridgeUploadQueue.Item) extends CreateReply - case object AuthorizationError - extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - final case class CommonError(userMessage: String) extends CreateReply with DomainError - } - - sealed trait GetByIdReply - object GetByIdReply { - type Error = GetByIdReply with DomainError - - final case class Entity(x: BridgeUploadQueue.Item) extends GetByIdReply - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case object NotFoundError extends GetByIdReply with DomainError.NotFoundError with DefaultNotFoundError - final case class CommonError(userMessage: String) extends GetByIdReply with DomainError - } - - sealed trait GetListReply - object GetListReply { - type Error = GetListReply with DomainError - - final case class EntityList(xs: Seq[BridgeUploadQueue.Item], totalFound: Int) extends GetListReply - - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait ResetReply - object ResetReply { - type Error = ResetReply with DomainError - - final case class Updated(updated: BridgeUploadQueue.Item) extends ResetReply - case object AuthorizationError extends ResetReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case object NotFoundError extends ResetReply with DefaultNotFoundError with DomainError.NotFoundError - final case class CommonError(userMessage: String) extends ResetReply with DomainError - } -} - -trait QueueUploadService { - - import QueueUploadService._ - - def create(kind: String, tag: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def getById(kind: String, tag: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def reset(kind: String, tag: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ResetReply] - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/SlotArmService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/SlotArmService.scala deleted file mode 100644 index 44e50da..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/SlotArmService.scala +++ /dev/null @@ -1,130 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.SlotArm - -import scala.concurrent.Future - -object SlotArmService { - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - trait DefaultNotFoundError { - def userMessage: String = "SlotArm not found" - } - - sealed trait GetByIdReply - object GetByIdReply { - - final case class Entity(x: SlotArm) extends GetByIdReply - - type Error = GetByIdReply with DomainError - - case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - - final case class CommonError(userMessage: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]) - extends GetByIdReply with DomainError - } - - sealed trait GetListReply - object GetListReply { - type Error = GetListReply with DomainError - - final case class EntityList(xs: Seq[SlotArm], totalFound: Int) extends GetListReply - - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait UpdateReply - object UpdateReply { - - final case class Updated(updated: SlotArm) extends UpdateReply - - type Error = UpdateReply with DomainError - - case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - - final case class AlreadyExistsError(x: SlotArm) extends UpdateReply with DomainError { - val userMessage = s"The arm with such name of trial already exists." - } - - implicit def toPhiString(reply: UpdateReply): PhiString = reply match { - case Updated(x) => phi"Updated($x)" - case x: Error => DomainError.toPhiString(x) - } - } - - sealed trait CreateReply - object CreateReply { - final case class Created(x: SlotArm) extends CreateReply - - type Error = CreateReply with DomainError - - case object AuthorizationError - extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends CreateReply with DomainError - - final case class AlreadyExistsError(x: SlotArm) extends CreateReply with DomainError { - val userMessage = s"The arm with this name of trial already exists." - } - - implicit def toPhiString(reply: CreateReply): PhiString = reply match { - case Created(x) => phi"Created($x)" - case x: Error => DomainError.toPhiString(x) - } - } - - sealed trait DeleteReply - object DeleteReply { - case object Deleted extends DeleteReply - - type Error = DeleteReply with DomainError - - case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends DeleteReply with DomainError - } -} - -trait SlotArmService { - - import SlotArmService._ - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def getById(armId: LongId[SlotArm])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def create(draftSlotArm: SlotArm)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def update(origSlotArm: SlotArm, draftSlotArm: SlotArm)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def delete(id: LongId[SlotArm])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala deleted file mode 100644 index 8af159d..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala +++ /dev/null @@ -1,28 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.Sorting -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuidomain.entities.StudyDesign - -import scala.concurrent.Future - -object StudyDesignService { - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[StudyDesign], totalFound: Int) extends GetListReply - - case object AuthorizationError extends GetListReply with DomainError.AuthorizationError { - def userMessage: String = "Access denied" - } - } -} - -trait StudyDesignService { - - import StudyDesignService._ - - def getAll(sorting: Option[Sorting] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/TrialHistoryService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/TrialHistoryService.scala deleted file mode 100644 index 96ff96d..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/TrialHistoryService.scala +++ /dev/null @@ -1,45 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import java.time.LocalDateTime - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.StringId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuidomain.entities.{Trial, TrialHistory} - -import scala.concurrent.Future - -object TrialHistoryService { - - trait DefaultNotFoundError { - def userMessage: String = "Trial not found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[TrialHistory], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListReply - - final case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - -} - -trait TrialHistoryService { - - import TrialHistoryService._ - - def getListByTrialId(id: StringId[Trial], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/TrialIssueService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/TrialIssueService.scala deleted file mode 100644 index 433c1bc..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/TrialIssueService.scala +++ /dev/null @@ -1,95 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import java.time.LocalDateTime - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuidomain.entities.{Trial, TrialIssue} - -import scala.concurrent.Future - -object TrialIssueService { - - trait DefaultNotFoundError { - def userMessage: String = "TrialIssue not found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait CreateReply - object CreateReply { - type Error = CreateReply with DomainError - final case class Created(x: TrialIssue) extends CreateReply - case object AuthorizationError - extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - final case class CommonError(userMessage: String) extends CreateReply with DomainError - } - - sealed trait GetByIdReply - object GetByIdReply { - type Error = GetByIdReply with DomainError - final case class Entity(x: TrialIssue) extends GetByIdReply - case object NotFoundError extends GetByIdReply with DomainError.NotFoundError with DefaultNotFoundError - final case class CommonError(userMessage: String) extends GetByIdReply with DomainError - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait GetListByTrialIdReply - object GetListByTrialIdReply { - type Error = GetListByTrialIdReply with DomainError - final case class EntityList(xs: Seq[TrialIssue], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListByTrialIdReply - case object NotFoundError extends GetListByTrialIdReply with DomainError.NotFoundError with DefaultNotFoundError - case object AuthorizationError - extends GetListByTrialIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait UpdateReply - object UpdateReply { - type Error = UpdateReply with DomainError - final case class Updated(updated: TrialIssue) extends UpdateReply - case object AuthorizationError - extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - } - - sealed trait DeleteReply - object DeleteReply { - type Error = DeleteReply with DomainError - case object Deleted extends DeleteReply - case object AuthorizationError - extends DeleteReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case object NotFoundError extends DeleteReply with DomainError.NotFoundError with DefaultNotFoundError - final case class CommonError(userMessage: String) extends DeleteReply with DomainError - } -} - -trait TrialIssueService { - - import TrialIssueService._ - - def create(draft: TrialIssue)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] - - def getById(trialId: StringId[Trial], id: LongId[TrialIssue])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def getListByTrialId(trialId: StringId[Trial], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListByTrialIdReply] - - def update(orig: TrialIssue, draft: TrialIssue)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def delete(trialId: StringId[Trial], id: LongId[TrialIssue])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala deleted file mode 100644 index 9ae1c10..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala +++ /dev/null @@ -1,158 +0,0 @@ -package xyz.driver.pdsuidomain.services - -import java.time.LocalDateTime - -import akka.NotUsed -import akka.stream.scaladsl.Source -import akka.util.ByteString -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.patient.CancerType -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain.StringId -import xyz.driver.pdsuicommon.error.DomainError -import xyz.driver.pdsuicommon.logging._ -import xyz.driver.pdsuidomain.entities.{Trial, TrialCreationRequest} -import xyz.driver.pdsuidomain.entities.export.trial.ExportTrialWithLabels - -import scala.concurrent.Future - -object TrialService { - - trait DefaultNotFoundError { - def userMessage: String = "Trial not found" - } - - trait DefaultAccessDeniedError { - def userMessage: String = "Access denied" - } - - sealed trait GetListReply - object GetListReply { - final case class EntityList(xs: Seq[Trial], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListReply - - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait GetByIdReply - object GetByIdReply { - final case class Entity(x: Trial) extends GetByIdReply - - type Error = GetByIdReply with DomainError - - case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - - final case class CommonError(userMessage: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]) - extends GetByIdReply with DomainError - - implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { - case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x) => phi"GetByIdReply.Entity($x)" - } - } - - sealed trait GetTrialWithLabelsReply - object GetTrialWithLabelsReply { - type Error = GetTrialWithLabelsReply with DomainError - - final case class Entity(x: ExportTrialWithLabels) extends GetTrialWithLabelsReply - - case object NotFoundError extends GetTrialWithLabelsReply with DomainError.NotFoundError { - def userMessage: String = "Trial not found" - } - - case object AuthorizationError - extends GetTrialWithLabelsReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait GetTrialsWithLabelsReply - object GetTrialsWithLabelsReply { - type Error = GetTrialsWithLabelsReply with DomainError - - final case class EntityList(xs: Seq[ExportTrialWithLabels]) extends GetTrialsWithLabelsReply - - case object NotFoundError extends GetTrialsWithLabelsReply with DomainError.NotFoundError { - def userMessage: String = "Trials for disease are not found" - } - - case object AuthorizationError - extends GetTrialsWithLabelsReply with DomainError.AuthorizationError with DefaultAccessDeniedError - } - - sealed trait UpdateReply - object UpdateReply { - type Error = UpdateReply with DomainError - - final case class Updated(updated: Trial) extends UpdateReply - - case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError - - case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - - final case class CommonError(userMessage: String) extends UpdateReply with DomainError - - implicit def toPhiString(reply: UpdateReply): PhiString = reply match { - case Updated(x) => phi"Updated($x)" - case x: Error => DomainError.toPhiString(x) - } - } -} - -trait TrialService { - - import TrialService._ - - def getById(id: StringId[Trial])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] - - def getTrialWithLabels(trialId: StringId[Trial], cancerType: CancerType)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetTrialWithLabelsReply] - - def getTrialsWithLabels(cancerType: CancerType)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetTrialsWithLabelsReply] - - def getPdfSource(trialId: StringId[Trial])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Source[ByteString, NotUsed]] - - def getHtmlSource(trialId: StringId[Trial])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Source[ByteString, NotUsed]] - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] - - def update(origTrial: Trial, draftTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def start(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def submit(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def restart(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def flag(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def resolve(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def archive(origTrial: Trial, comment: Option[String])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def unassign(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] - - def addTrial(trial: TrialCreationRequest)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Trial] -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeEligibilityVerificationService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeEligibilityVerificationService.scala deleted file mode 100644 index 35c518c..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeEligibilityVerificationService.scala +++ /dev/null @@ -1,32 +0,0 @@ -package xyz.driver.pdsuidomain.services.fake - -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.core.{Id, generators} -import xyz.driver.entities.patient -import xyz.driver.entities.patient.Patient -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities.eligibility.MismatchRankedLabels -import xyz.driver.pdsuidomain.entities.{EligibilityArm, eligibility} -import xyz.driver.pdsuidomain.services.EligibilityVerificationService - -import scala.concurrent.Future -import scalaz.ListT - -class FakeEligibilityVerificationService extends EligibilityVerificationService { - - override def getMatchedPatients()( - implicit ctx: AuthorizedServiceRequestContext[AuthUserInfo]): ListT[Future, eligibility.MatchedPatient] = - ListT.listT[Future]( - Future.successful(List(xyz.driver.pdsuidomain.fakes.entities.eligibility.nextMatchedPatient()))) - - override def getMismatchRankedLabels(patientId: Id[Patient], - cancerType: patient.CancerType, - excludedArms: Seq[LongId[EligibilityArm]])( - implicit ctx: AuthorizedServiceRequestContext[AuthUserInfo]): Future[eligibility.MismatchRankedLabels] = - Future.successful( - MismatchRankedLabels( - generators.seqOf(xyz.driver.pdsuidomain.fakes.entities.eligibility.nextLabelMismatchRank()), - labelVersion = generators.nextInt(10) - )) -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala deleted file mode 100644 index 221e56c..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala +++ /dev/null @@ -1,136 +0,0 @@ -package xyz.driver.pdsuidomain.services.fake - -import java.time.LocalDateTime - -import akka.NotUsed -import akka.stream.scaladsl.Source -import akka.util.ByteString -import xyz.driver.core.generators -import xyz.driver.core.rest.AuthorizedServiceRequestContext -import xyz.driver.entities.labels.Label -import xyz.driver.entities.patient.CancerType -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} -import xyz.driver.pdsuidomain.entities.export.trial.{ExportTrialArm, ExportTrialLabelCriterion, ExportTrialWithLabels} -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.TrialService - -import scala.concurrent.Future - -class FakeTrialService extends TrialService { - - import TrialService._ - - private val trial = Trial( - id = StringId(""), - externalId = UuidId(), - status = Trial.Status.New, - assignee = None, - previousStatus = None, - previousAssignee = None, - lastActiveUserId = None, - lastUpdate = LocalDateTime.now(), - phase = "", - hypothesisId = None, - studyDesignId = None, - originalStudyDesign = None, - isPartner = false, - overview = None, - overviewTemplate = "", - isUpdated = false, - title = "", - originalTitle = "" - ) - - def getById(id: StringId[Trial])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] = - Future.successful( - GetByIdReply.Entity(trial) - ) - - def getPdfSource(trialId: StringId[Trial])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo] - ): Future[Source[ByteString, NotUsed]] = - Future.failed(new NotImplementedError("fake PDF download is not implemented")) - - def getHtmlSource(trialId: StringId[Trial])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo] - ): Future[Source[ByteString, NotUsed]] = - Future.failed(new NotImplementedError("fake HTML download is not implemented")) - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = - Future.successful(GetListReply.EntityList(Seq(trial), 1, None)) - - override def getTrialWithLabels(trialId: StringId[Trial], cancerType: CancerType)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetTrialWithLabelsReply] = - Future.successful(GetTrialWithLabelsReply.Entity(nextExportTrialWithLabels())) - - override def getTrialsWithLabels(cancerType: CancerType)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetTrialsWithLabelsReply] = - Future.successful(GetTrialsWithLabelsReply.EntityList(generators.seqOf(nextExportTrialWithLabels()))) - - private def nextExportTrialWithLabels() = - ExportTrialWithLabels( - StringId[Trial]("NCT" + generators.nextInt(999999).toString), - UuidId[Trial](generators.nextUuid()), - LocalDateTime.now(), - labelVersion = 1L, - generators.listOf( - new ExportTrialArm( - LongId[EligibilityArm](generators.nextInt(999999).toLong), - generators.nextName().value, - generators.listOf(generators.oneOf("adenocarcinoma", "breast", "prostate")) - )), - generators.listOf( - new ExportTrialLabelCriterion( - LongId[Criterion](generators.nextInt(999999).toLong), - generators.nextOption(generators.nextBoolean()), - LongId[Label](generators.nextInt(999999).toLong), - generators.setOf(LongId[EligibilityArm](generators.nextInt(999999).toLong)), - generators.nextName().value, - generators.nextBoolean(), - generators.nextBoolean(), - generators.nextOption(generators.nextBoolean()) - )) - ) - - def update(origTrial: Trial, draftTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - Future.successful(UpdateReply.Updated(draftTrial)) - - def start(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - update(origTrial, origTrial) - - def submit(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - update(origTrial, origTrial) - - def restart(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - update(origTrial, origTrial) - - def flag(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - update(origTrial, origTrial) - - def resolve(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - update(origTrial, origTrial) - - def archive(origTrial: Trial, comment: Option[String])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - update(origTrial, origTrial) - - def unassign(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - update(origTrial, origTrial) - - def addTrial(newTrial: TrialCreationRequest)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Trial] = - Future.successful(trial) -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestArmService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestArmService.scala deleted file mode 100644 index 87e2bab..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestArmService.scala +++ /dev/null @@ -1,85 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.marshalling.Marshal -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.ArmService - -class RestArmService(transport: ServiceTransport, baseUri: Uri)(implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends ArmService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.arm._ - import xyz.driver.pdsuidomain.services.ArmService._ - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - val request = HttpRequest( - HttpMethods.GET, - endpointUri(baseUri, "/v1/arm", filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[Arm]](response) - } yield { - GetListReply.EntityList(reply.items, reply.meta.itemsCount) - } - } - - def getById(armId: LongId[Arm])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/arm/$armId")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Arm](response) - } yield { - GetByIdReply.Entity(reply) - } - } - - def create(draftArm: Arm)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] = { - for { - entity <- Marshal(draftArm).to[RequestEntity] - request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/arm")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Arm](response) - } yield { - CreateReply.Created(reply) - } - } - - def update(origArm: Arm, draftArm: Arm)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = { - val id = origArm.id - val request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/arm/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Arm](response) - } yield { - UpdateReply.Updated(reply) - } - } - - def delete(id: LongId[Arm])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] = { - val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/arm/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - _ <- apiResponse[HttpEntity](response) - } yield { - DeleteReply.Deleted - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestCriterionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestCriterionService.scala deleted file mode 100644 index 33be27e..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestCriterionService.scala +++ /dev/null @@ -1,88 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.marshalling.Marshal -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.CriterionService - -class RestCriterionService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends CriterionService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.criterion._ - import xyz.driver.pdsuidomain.services.CriterionService._ - - def create(draftRichCriterion: RichCriterion)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] = { - for { - entity <- Marshal(draftRichCriterion).to[RequestEntity] - request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/criterion")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[RichCriterion](response) - } yield { - CreateReply.Created(reply) - } - } - - def getById(id: LongId[Criterion])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/criterion/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[RichCriterion](response) - } yield { - GetByIdReply.Entity(reply) - } - } - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - val request = HttpRequest(HttpMethods.GET, - endpointUri(baseUri, - s"/v1/criterion", - filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[RichCriterion]](response) - } yield { - GetListReply.EntityList(reply.items, reply.meta.itemsCount, reply.meta.lastUpdate) - } - } - - def update(origRichCriterion: RichCriterion, draftRichCriterion: RichCriterion)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = { - val id = origRichCriterion.criterion.id - for { - entity <- Marshal(draftRichCriterion).to[RequestEntity] - request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/criterion/$id")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[RichCriterion](response) - } yield { - UpdateReply.Updated(reply) - } - } - - def delete(id: LongId[Criterion])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] = { - val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/criterion/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - _ <- apiResponse[HttpEntity](response) - } yield { - DeleteReply.Deleted - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestDocumentService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestDocumentService.scala deleted file mode 100644 index bfe5e8f..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestDocumentService.scala +++ /dev/null @@ -1,121 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.marshalling.Marshal -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.DocumentService - -class RestDocumentService(transport: ServiceTransport, baseUri: Uri)(implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends DocumentService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.document._ - import xyz.driver.pdsuidomain.services.DocumentService._ - - def getById(id: LongId[Document])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/document/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Document](response) - } yield { - GetByIdReply.Entity(reply) - } - } - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - - val request = HttpRequest(HttpMethods.GET, - endpointUri(baseUri, - "/v1/document", - filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[Document]](response) - } yield { - GetListReply.EntityList(reply.items, reply.meta.itemsCount, reply.meta.lastUpdate) - } - } - - def create(draftDocument: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] = { - for { - entity <- Marshal(draftDocument).to[RequestEntity] - request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/document")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Document](response) - } yield { - CreateReply.Created(reply) - } - } - - def update(orig: Document, draft: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = { - for { - entity <- Marshal(draft).to[RequestEntity] - request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/document/${orig.id}")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Document](response) - } yield { - UpdateReply.Updated(reply) - } - } - - def delete(id: LongId[Document])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] = { - val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/document/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - _ <- apiResponse[HttpEntity](response) - } yield { - DeleteReply.Deleted - } - } - - private def editAction(orig: Document, action: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = { - val id = orig.id.toString - val request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, s"/v1/document/$id/$action")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Document](response) - } yield { - UpdateReply.Updated(reply) - } - } - - def start(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "start") - def submit(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "submit") - def restart(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "restart") - def flag(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "flag") - def resolve(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "resolve") - def unassign(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "unassign") - def archive(orig: Document)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "archive") - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestDocumentTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestDocumentTypeService.scala deleted file mode 100644 index 6157cc3..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestDocumentTypeService.scala +++ /dev/null @@ -1,33 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities.DocumentType -import xyz.driver.pdsuidomain.services.DocumentTypeService - -class RestDocumentTypeService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends DocumentTypeService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.document.documentTypeFormat - import xyz.driver.pdsuidomain.services.DocumentTypeService._ - - def getAll(sorting: Option[Sorting] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, "/v1/document-type", sortingQuery(sorting))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[DocumentType]](response) - } yield { - GetListReply.EntityList(reply.items, reply.meta.itemsCount) - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilitySnapshotService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilitySnapshotService.scala deleted file mode 100644 index 2187ec2..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilitySnapshotService.scala +++ /dev/null @@ -1,34 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import akka.http.scaladsl.model.{HttpMethods, HttpRequest, Uri} -import akka.stream.Materializer -import xyz.driver.core.rest.{AuthorizedServiceRequestContext, ServiceTransport} -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuidomain.entities.eligibility.EligibleTrial -import xyz.driver.pdsuidomain.entities.{Patient, eligibility} -import xyz.driver.pdsuidomain.services.EligibilitySnapshotService - -import scala.concurrent.{ExecutionContext, Future} - -class RestEligibilitySnapshotService(transport: ServiceTransport, baseUrl: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) extends EligibilitySnapshotService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import spray.json.DefaultJsonProtocol._ - import xyz.driver.pdsuidomain.formats.json.eligibility._ - - override def eligibilitySnapshot(patientId: UuidId[Patient]) - (implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): - Future[Seq[eligibility.EligibleTrial]] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUrl, s"/v1/patient/$patientId/eligibilitySnapshot")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Seq[EligibleTrial]](response) - } yield { - reply - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilityVerificationService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilityVerificationService.scala deleted file mode 100644 index e057c55..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilityVerificationService.scala +++ /dev/null @@ -1,53 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import akka.http.scaladsl.model.Uri -import akka.stream.Materializer -import spray.json.DefaultJsonProtocol -import xyz.driver.core.Id -import xyz.driver.core.rest.{AuthorizedServiceRequestContext, RestService, ServiceTransport} -import xyz.driver.entities.patient -import xyz.driver.entities.patient.Patient -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities.eligibility.{MatchedPatient, MismatchRankedLabels} -import xyz.driver.pdsuidomain.entities.{EligibilityArm, eligibility} -import xyz.driver.pdsuidomain.services.EligibilityVerificationService - -import scala.concurrent.{ExecutionContext, Future} -import scalaz.ListT -import scalaz.Scalaz.futureInstance - -class RestEligibilityVerificationService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext -) extends EligibilityVerificationService with RestService { - - import DefaultJsonProtocol._ - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.eligibility._ - - override def getMatchedPatients()( - implicit ctx: AuthorizedServiceRequestContext[AuthUserInfo]): ListT[Future, eligibility.MatchedPatient] = { - val request = get(baseUri, s"/v1/patients") - listResponse[MatchedPatient](transport.sendRequest(ctx)(request)) - } - - override def getMismatchRankedLabels(patientId: Id[Patient], - cancerType: patient.CancerType, - excludedArms: Seq[LongId[EligibilityArm]])( - implicit ctx: AuthorizedServiceRequestContext[AuthUserInfo]): Future[eligibility.MismatchRankedLabels] = { - - val query = Seq("disease" -> cancerType.toString.toUpperCase) ++ (if (excludedArms.nonEmpty) { - Seq( - "ineligible_arms" -> excludedArms - .map(_.id) - .mkString(",")) - } else { - Seq.empty[(String, String)] - }) - - val request = get(baseUri, s"/v1/patients/$patientId/labels", query) - optionalResponse[MismatchRankedLabels](transport.sendRequest(ctx)(request)) - .getOrElse(throw new Exception(s"The data of patient $patientId is not ready yet")) - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestExtractedDataService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestExtractedDataService.scala deleted file mode 100644 index 24c5436..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestExtractedDataService.scala +++ /dev/null @@ -1,100 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.marshalling.Marshal -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.entities.export.patient.ExportPatientWithLabels -import xyz.driver.pdsuidomain.services.ExtractedDataService -import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.formats.json.export._ - -class RestExtractedDataService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends ExtractedDataService with RestHelper { - - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.extracteddata._ - import xyz.driver.pdsuidomain.services.ExtractedDataService._ - - def getById(id: LongId[ExtractedData])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/extracted-data/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[RichExtractedData](response) - } yield { - GetByIdReply.Entity(reply) - } - } - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - val request = HttpRequest(HttpMethods.GET, - endpointUri(baseUri, - "/v1/extracted-data", - filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[RichExtractedData]](response) - } yield { - GetListReply.EntityList(reply.items, reply.meta.itemsCount) - } - } - - def create(draftRichExtractedData: RichExtractedData)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] = { - for { - entity <- Marshal(draftRichExtractedData).to[RequestEntity] - request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/extracted-data")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[RichExtractedData](response) - } yield { - CreateReply.Created(reply) - } - } - def update(origRichExtractedData: RichExtractedData, draftRichExtractedData: RichExtractedData)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = { - val id = origRichExtractedData.extractedData.id - for { - entity <- Marshal(draftRichExtractedData).to[RequestEntity] - request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/extracted-data/$id")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[RichExtractedData](response) - } yield { - UpdateReply.Updated(reply) - } - } - - def delete(id: LongId[ExtractedData])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] = { - val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/export-data/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - _ <- apiResponse[HttpEntity](response) - } yield { - DeleteReply.Deleted - } - } - - def getPatientLabels(id: UuidId[Patient])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetPatientLabelsReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/export/patient/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ExportPatientWithLabels](response) - } yield { - GetPatientLabelsReply.Entity(reply) - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala deleted file mode 100644 index 8ed2651..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala +++ /dev/null @@ -1,107 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.model.{HttpResponse, ResponseEntity, StatusCodes, Uri} -import akka.http.scaladsl.unmarshalling.{Unmarshal, Unmarshaller} -import akka.stream.Materializer -import xyz.driver.core.rest.errors.{InvalidActionException, InvalidInputException, ResourceNotFoundException} -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterBinaryOperation, SearchFilterExpr, SearchFilterNAryOperation, Sorting, SortingOrder} -import xyz.driver.pdsuicommon.error._ - -trait RestHelper { - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import ErrorsResponse._ - - implicit protected val materializer: Materializer - implicit protected val exec: ExecutionContext - - protected def endpointUri(baseUri: Uri, path: String) = - baseUri.withPath(Uri.Path(path)) - - protected def endpointUri(baseUri: Uri, path: String, query: Seq[(String, String)]) = - baseUri.withPath(Uri.Path(path)).withQuery(Uri.Query(query: _*)) - - def sortingQuery(sorting: Option[Sorting]): Seq[(String, String)] = { - def dimensionQuery(dimension: Sorting.Dimension) = { - val ord = dimension.order match { - case SortingOrder.Ascending => "" - case SortingOrder.Descending => "-" - } - s"$ord${dimension.name}" - } - - sorting match { - case None => Seq.empty - case Some(dimension: Sorting.Dimension) => Seq("sort" -> dimensionQuery(dimension)) - case Some(Sorting.Sequential(dimensions)) => Seq("sort" -> dimensions.map(dimensionQuery).mkString(",")) - } - } - - def filterQuery(expr: SearchFilterExpr): Seq[(String, String)] = { - def opToString(op: SearchFilterBinaryOperation) = op match { - case SearchFilterBinaryOperation.Eq => "eq" - case SearchFilterBinaryOperation.NotEq => "ne" - case SearchFilterBinaryOperation.Like => "like" - case SearchFilterBinaryOperation.Gt => "gt" - case SearchFilterBinaryOperation.GtEq => "ge" - case SearchFilterBinaryOperation.Lt => "lt" - case SearchFilterBinaryOperation.LtEq => "le" - } - - def exprToQuery(expr: SearchFilterExpr): Seq[(String, String)] = expr match { - case SearchFilterExpr.Empty => Seq.empty - case SearchFilterExpr.Atom.Binary(dimension, op, value) => - Seq("filters" -> s"${dimension.tableName.fold("")(t => s"$t.") + dimension.name} ${opToString(op)} $value") - case SearchFilterExpr.Atom.NAry(dimension, SearchFilterNAryOperation.In, values) => - Seq("filters" -> s"${dimension.tableName.fold("")(t => s"$t.") + dimension.name} in ${values.mkString(",")}") - case SearchFilterExpr.Intersection(ops) => - ops.flatMap(op => exprToQuery(op)) - case expr => sys.error(s"No parser available for filter expression $expr.") - } - - exprToQuery(expr) - } - - def paginationQuery(pagination: Option[Pagination]): Seq[(String, String)] = pagination match { - case None => Seq.empty - case Some(pp) => - Seq( - "pageNumber" -> pp.pageNumber.toString, - "pageSize" -> pp.pageSize.toString - ) - } - - /** Utility method to parse responses from records-acquisition-server. - * - * Non-2xx HTTP error codes will be cause the returned future to fail with a corresponding - * `DomainException`. - * @tparam ApiReply The type of the serialized reply object, contained in the HTTP entity - * @param response The HTTP response to parse. - * @param unmarshaller An unmarshaller that converts a successful response to an api reply. - */ - def apiResponse[ApiReply](response: HttpResponse)( - implicit unmarshaller: Unmarshaller[ResponseEntity, ApiReply]): Future[ApiReply] = { - - def extractErrorMessage(response: HttpResponse): Future[String] = { - Unmarshal(response.entity) - .to[ErrorsResponse] - .transform( - response => response.errors.map(_.message).mkString(", "), - ex => InvalidInputException(s"Response has invalid format: ${ex.getMessage}") - ) - } - - if (response.status.isSuccess) { - Unmarshal(response.entity).to[ApiReply] - } else { - extractErrorMessage(response).flatMap { message => - Future.failed(response.status match { - case StatusCodes.Forbidden => InvalidActionException(message) - case StatusCodes.NotFound => ResourceNotFoundException(message) - case other => - InvalidInputException(s"Unhandled domain error for HTTP status ${other.value}. $message") - }) - } - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala deleted file mode 100644 index 11adb8f..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala +++ /dev/null @@ -1,60 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import akka.http.scaladsl.marshalling.Marshal - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest._ -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities.Hypothesis -import xyz.driver.pdsuidomain.services.HypothesisService - -class RestHypothesisService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends HypothesisService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.hypothesis._ - import xyz.driver.pdsuidomain.services.HypothesisService._ - - def getAll(sorting: Option[Sorting] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, "/v1/hypothesis", sortingQuery(sorting))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[Hypothesis]](response) - } yield { - GetListReply.EntityList(reply.items, reply.meta.itemsCount) - } - } - - def create(draftHypothesis: Hypothesis)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] = { - for { - entity <- Marshal(draftHypothesis).to[RequestEntity] - request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/hypothesis")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Hypothesis](response) - } yield { - CreateReply.Created(reply) - } - } - - def delete(id: UuidId[Hypothesis])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] = { - val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/hypothesis/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - _ <- apiResponse[HttpEntity](response) - } yield { - DeleteReply.Deleted - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionService.scala deleted file mode 100644 index c4add4a..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionService.scala +++ /dev/null @@ -1,88 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.marshalling.Marshal -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.InterventionService - -class RestInterventionService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends InterventionService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.intervention._ - import xyz.driver.pdsuidomain.services.InterventionService._ - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - val request = HttpRequest(HttpMethods.GET, - endpointUri(baseUri, - "/v1/intervention", - filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[InterventionWithArms]](response) - } yield { - GetListReply.EntityList(reply.items, reply.meta.itemsCount) - } - } - - def getById(id: LongId[Intervention])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/intervention/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[InterventionWithArms](response) - } yield { - GetByIdReply.Entity(reply) - } - } - - def update(origIntervention: InterventionWithArms, draftIntervention: InterventionWithArms)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = { - val id = origIntervention.intervention.id - for { - entity <- Marshal(draftIntervention).to[RequestEntity] - request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/intervention/$id")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[InterventionWithArms](response) - } yield { - UpdateReply.Updated(reply) - } - } - - def create(draftIntervention: InterventionWithArms)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] = { - for { - entity <- Marshal(draftIntervention).to[RequestEntity] - request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/intervention")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[InterventionWithArms](response) - } yield { - CreateReply.Created(reply) - } - } - - def delete(id: LongId[Intervention])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[DeleteReply] = { - val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/intervention/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - _ <- apiResponse[HttpEntity](response) - } yield { - DeleteReply.Deleted - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionTypeService.scala deleted file mode 100644 index 825b936..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionTypeService.scala +++ /dev/null @@ -1,37 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest._ -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities.InterventionType -import xyz.driver.pdsuidomain.services.InterventionTypeService - -class RestInterventionTypeService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends InterventionTypeService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.intervention.interventionTypeFormat - import xyz.driver.pdsuidomain.services.InterventionTypeService._ - - def getAll(sorting: Option[Sorting] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, "/v1/intervention-type", sortingQuery(sorting))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[InterventionType]](response) - } yield { - { - val domain = reply.items - GetListReply.EntityList(domain.toList, reply.meta.itemsCount) - } - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestMedicalRecordService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestMedicalRecordService.scala deleted file mode 100644 index 6af6707..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestMedicalRecordService.scala +++ /dev/null @@ -1,129 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import akka.NotUsed -import akka.stream.scaladsl.Source -import akka.util.ByteString - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.marshalling.Marshal -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.MedicalRecordService - -class RestMedicalRecordService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends MedicalRecordService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.record._ - import xyz.driver.pdsuidomain.services.MedicalRecordService._ - - def getById(recordId: LongId[MedicalRecord])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/record/$recordId")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[MedicalRecord](response) - } yield { - GetByIdReply.Entity(reply) - } - } - - def getPdfSource(recordId: LongId[MedicalRecord])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo] - ): Future[Source[ByteString, NotUsed]] = { - - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/record/$recordId/source")) - - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[HttpEntity](response) - } yield { - reply.dataBytes.mapMaterializedValue(_ => NotUsed) - } - } - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - - val request = HttpRequest( - HttpMethods.GET, - endpointUri(baseUri, "/v1/record", filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[MedicalRecord]](response) - } yield { - GetListReply.EntityList(reply.items, reply.meta.itemsCount, reply.meta.lastUpdate) - } - } - - def create(draftRecord: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[CreateReply] = { - for { - entity <- Marshal(draftRecord).to[RequestEntity] - request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/record")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[MedicalRecord](response) - } yield { - CreateReply.Created(reply) - } - } - - def update(origRecord: MedicalRecord, draftRecord: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = { - val id = origRecord.id.toString - for { - entity <- Marshal(draftRecord).to[RequestEntity] - request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/record/$id")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[MedicalRecord](response) - } yield { - UpdateReply.Updated(reply) - } - } - - private def editAction(orig: MedicalRecord, action: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = { - val id = orig.id.toString - val request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, s"/v1/record/$id/$action")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[MedicalRecord](response) - } yield { - UpdateReply.Updated(reply) - } - } - - def start(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "start") - def submit(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "submit") - def restart(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "restart") - def flag(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "flag") - def resolve(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "resolve") - def unassign(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "unassign") - def archive(orig: MedicalRecord)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - editAction(orig, "archive") - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientCriterionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientCriterionService.scala deleted file mode 100644 index cc66142..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientCriterionService.scala +++ /dev/null @@ -1,81 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import akka.http.scaladsl.marshalling.Marshal -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, _} -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.PatientCriterionService - -import scala.concurrent.{ExecutionContext, Future} - -class RestPatientCriterionService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends PatientCriterionService with RestHelper { - - import spray.json.DefaultJsonProtocol._ - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.patientcriterion._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - - def getAll(patientId: UuidId[Patient], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[RichPatientCriterion]] = { - val request = HttpRequest(HttpMethods.GET, - endpointUri(baseUri, - s"/v1/patient/$patientId/criterion", - filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(Some(pagination)))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[RichPatientCriterion]](response) - } yield { - reply - } - } - - def getById(patientId: UuidId[Patient], id: LongId[PatientCriterion])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Option[RichPatientCriterion]] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/patient/$patientId/criterion/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - entity <- apiResponse[RichPatientCriterion](response) - } yield { - Option(entity) - } - } - - def updateList(patientId: UuidId[Patient], draftEntities: List[DraftPatientCriterion])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Unit] = { - for { - entity <- Marshal(draftEntities).to[RequestEntity] - request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/patient/$patientId/criterion")) - .withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - _ <- apiResponse[RichPatientCriterion](response) - } yield { - () - } - } - - def update(origEntity: PatientCriterion, draftEntity: PatientCriterion, patientId: UuidId[Patient])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[RichPatientCriterion] = { - for { - entity <- Marshal(draftEntity).to[RequestEntity] - request = HttpRequest( - HttpMethods.PATCH, - endpointUri(baseUri, s"/v1/patient/$patientId/criterion/${origEntity.criterionId}")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - entity <- apiResponse[RichPatientCriterion](response) - } yield { - entity - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientLabelService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientLabelService.scala deleted file mode 100644 index 932e123..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientLabelService.scala +++ /dev/null @@ -1,84 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import akka.http.scaladsl.marshalling.Marshal -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.entities.labels.Label -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, _} -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.PatientLabelService - -import scala.concurrent.{ExecutionContext, Future} - -class RestPatientLabelService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends PatientLabelService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.patientlabel._ - - def getAll(patientId: UuidId[Patient], - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[RichPatientLabel]] = { - val request = HttpRequest(HttpMethods.GET, - endpointUri(baseUri, - s"/v1/patient/$patientId/label", - filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(Some(pagination)))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[RichPatientLabel]](response) - } yield { - reply - } - } - - def getDefiningCriteriaList(patientId: UuidId[Patient], - hypothesisId: UuidId[Hypothesis], - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo] - ): Future[ListResponse[PatientLabel]] = { - val request = HttpRequest(HttpMethods.GET, - endpointUri(baseUri, s"/patient/$patientId/hypothesis", paginationQuery(Some(pagination)))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[PatientLabel]](response) - } yield { - reply - } - } - - def getByLabelIdOfPatient(patientId: UuidId[Patient], labelId: LongId[Label])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Option[RichPatientLabel]] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/patient/$patientId/label/$labelId")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - entity <- apiResponse[RichPatientLabel](response) - } yield { - Option(entity) - } - } - - def update(origPatientLabel: PatientLabel, draftPatientLabel: PatientLabel)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[RichPatientLabel] = { - for { - entity <- Marshal(draftPatientLabel).to[RequestEntity] - request = HttpRequest( - HttpMethods.PATCH, - endpointUri(baseUri, s"/v1/patient/${origPatientLabel.patientId}/label/${origPatientLabel.labelId}")) - .withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - entity <- apiResponse[RichPatientLabel](response) - } yield { - entity - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientService.scala deleted file mode 100644 index 67f4e38..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestPatientService.scala +++ /dev/null @@ -1,78 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db.{Pagination, _} -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.services.PatientService - -class RestPatientService(transport: ServiceTransport, baseUri: Uri)(implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends PatientService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.patient._ - - def getById(id: UuidId[Patient])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Option[Patient]] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/patient/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - entity <- apiResponse[Patient](response) - } yield { - Option(entity) - } - } - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Pagination = Pagination.Default)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[ListResponse[Patient]] = { - val request = HttpRequest( - HttpMethods.GET, - endpointUri(baseUri, "/v1/patient", filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(Some(pagination)))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[Patient]](response) - } yield { - reply - } - } - - private def editAction(orig: Patient, action: String)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] = { - val id = orig.id.toString - val request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, s"/v1/patient/$id/$action")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - entity <- apiResponse[Patient](response) - } yield { - entity - } - } - - def unassign(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] = - editAction(origPatient, "unassign") - def start(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] = - editAction(origPatient, "start") - def submit(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] = - editAction(origPatient, "submit") - def restart(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] = - editAction(origPatient, "restart") - def flag(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] = - editAction(origPatient, "flag") - def resolve(origPatient: Patient)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Patient] = - editAction(origPatient, "resolve") -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestProviderTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestProviderTypeService.scala deleted file mode 100644 index ffde086..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestProviderTypeService.scala +++ /dev/null @@ -1,34 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities.ProviderType -import xyz.driver.pdsuidomain.services.ProviderTypeService - -class RestProviderTypeService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends ProviderTypeService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.record.providerTypeFormat - import xyz.driver.pdsuidomain.services.ProviderTypeService._ - - def getAll(sorting: Option[Sorting] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, "/v1/provider-type", sortingQuery(sorting))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[ProviderType]](response) - } yield { - GetListReply.EntityList(reply.items, reply.meta.itemsCount) - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestStudyDesignService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestStudyDesignService.scala deleted file mode 100644 index f8ce502..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestStudyDesignService.scala +++ /dev/null @@ -1,34 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest._ -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities.StudyDesign -import xyz.driver.pdsuidomain.services.StudyDesignService - -class RestStudyDesignService(transport: ServiceTransport, baseUri: Uri)( - implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends StudyDesignService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.studydesign._ - import xyz.driver.pdsuidomain.services.StudyDesignService._ - - def getAll(sorting: Option[Sorting] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, "/v1/study-design", sortingQuery(sorting))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[StudyDesign]](response) - } yield { - GetListReply.EntityList(reply.items, reply.meta.itemsCount) - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestTrialIssueService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestTrialIssueService.scala deleted file mode 100644 index b14d35b..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestTrialIssueService.scala +++ /dev/null @@ -1,103 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import akka.http.scaladsl.marshalling.Marshal -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import spray.json.RootJsonReader -import xyz.driver.core.rest.{AuthorizedServiceRequestContext, ServiceTransport} -import xyz.driver.entities.users -import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities.{Trial, TrialIssue} -import xyz.driver.pdsuidomain.services.TrialIssueService - -import scala.concurrent.ExecutionContext - -class RestTrialIssueService(transport: ServiceTransport, baseUri: Uri) - (implicit - protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends TrialIssueService with RestHelper{ - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.trialissue._ - import xyz.driver.pdsuidomain.services.TrialIssueService._ - - override def create(draft: TrialIssue) - (implicit requestContext: AuthorizedServiceRequestContext[users.AuthUserInfo]) = { - val trialId = draft.trialId - - implicit val jsonReader: RootJsonReader[TrialIssue] = trialIssueReader(trialId) - - for { - entity <- Marshal(draft).to[RequestEntity] - request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, s"/v1/trial/$trialId/issue")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[TrialIssue](response) - } yield { - CreateReply.Created(reply) - } - } - - override def getListByTrialId(trialId: StringId[Trial], - filter: SearchFilterExpr, - sorting: Option[Sorting], - pagination: Option[Pagination]) - (implicit requestContext: AuthorizedServiceRequestContext[users.AuthUserInfo]) = { - implicit val jsonReader: RootJsonReader[TrialIssue] = trialIssueReader(trialId) - - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/trial/$trialId/issue", - filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination)) - ) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[TrialIssue]](response) - } yield { - GetListByTrialIdReply.EntityList(reply.items, reply.meta.itemsCount, reply.meta.lastUpdate) - } - } - - override def getById(trialId: StringId[Trial], id: LongId[TrialIssue]) - (implicit requestContext: AuthorizedServiceRequestContext[users.AuthUserInfo]) = { - implicit val jsonReader: RootJsonReader[TrialIssue] = trialIssueReader(trialId) - - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/trial/$trialId/issue/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[TrialIssue](response) - } yield { - GetByIdReply.Entity(reply) - } - } - - override def update(orig: TrialIssue, draft: TrialIssue) - (implicit requestContext: AuthorizedServiceRequestContext[users.AuthUserInfo]) = { - val trialId = draft.trialId - val id = orig.id.id - - implicit val jsonReader: RootJsonReader[TrialIssue] = trialIssueReader(trialId) - - for { - entity <- Marshal(draft).to[RequestEntity] - request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/trial/$trialId/issue/$id")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[TrialIssue](response) - } yield { - UpdateReply.Updated(reply) - } - } - - override def delete(trialId: StringId[Trial], id: LongId[TrialIssue]) - (implicit requestContext: AuthorizedServiceRequestContext[users.AuthUserInfo]) = { - val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/trial/$trialId/issue/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - _ <- apiResponse[HttpEntity](response) - } yield { - DeleteReply.Deleted - } - } - -} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestTrialService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestTrialService.scala deleted file mode 100644 index 94e1c63..0000000 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestTrialService.scala +++ /dev/null @@ -1,173 +0,0 @@ -package xyz.driver.pdsuidomain.services.rest - -import scala.concurrent.{ExecutionContext, Future} -import akka.NotUsed -import akka.stream.scaladsl.Source -import akka.util.ByteString -import akka.http.scaladsl.marshalling.Marshal -import akka.http.scaladsl.model._ -import akka.stream.Materializer -import xyz.driver.core.rest.{Pagination => _, _} -import xyz.driver.pdsuicommon.db._ -import xyz.driver.pdsuicommon.domain._ -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.entities.export.trial.ExportTrialWithLabels -import xyz.driver.pdsuidomain.services.TrialService -import spray.json.DefaultJsonProtocol._ -import xyz.driver.entities.patient.CancerType -import xyz.driver.entities.users.AuthUserInfo -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.formats.json.export._ - -class RestTrialService(transport: ServiceTransport, baseUri: Uri)(implicit protected val materializer: Materializer, - protected val exec: ExecutionContext) - extends TrialService with RestHelper { - - import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ - import xyz.driver.pdsuidomain.formats.json.listresponse._ - import xyz.driver.pdsuidomain.formats.json.trial._ - import xyz.driver.pdsuidomain.services.TrialService._ - - def getById(id: StringId[Trial])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetByIdReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/trial/$id")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Trial](response) - } yield { - GetByIdReply.Entity(reply) - } - } - - def getTrialWithLabels(trialId: StringId[Trial], cancerType: CancerType)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetTrialWithLabelsReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/export/trial/$cancerType/$trialId")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ExportTrialWithLabels](response) - } yield { - GetTrialWithLabelsReply.Entity(reply) - } - } - - def getTrialsWithLabels(cancerType: CancerType)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetTrialsWithLabelsReply] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/export/trial/$cancerType")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Seq[ExportTrialWithLabels]](response) - } yield { - GetTrialsWithLabelsReply.EntityList(reply) - } - } - - def getPdfSource(trialId: StringId[Trial])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo] - ): Future[Source[ByteString, NotUsed]] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/trial/$trialId/source")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[HttpEntity](response) - } yield { - reply.dataBytes.mapMaterializedValue(_ => NotUsed) - } - } - - def getHtmlSource(trialId: StringId[Trial])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo] - ): Future[Source[ByteString, NotUsed]] = { - val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/trial/$trialId/source.html")) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[HttpEntity](response) - } yield { - reply.dataBytes.mapMaterializedValue(_ => NotUsed) - } - } - - def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[GetListReply] = { - val request = HttpRequest( - HttpMethods.GET, - endpointUri(baseUri, "/v1/trial", filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[ListResponse[Trial]](response) - } yield { - GetListReply.EntityList(reply.items, reply.meta.itemsCount, reply.meta.lastUpdate) - } - } - - def update(origTrial: Trial, draftTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = { - val id = origTrial.id.id - for { - entity <- Marshal(draftTrial).to[RequestEntity] - request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/trial/$id")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Trial](response) - } yield { - UpdateReply.Updated(reply) - } - } - - private def singleAction(origTrial: Trial, action: String, comment: Option[String] = None)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = { - - val query = comment match { - case Some(s) => Seq("comment" -> s) - case None => Seq.empty[(String, String)] - } - - val id = origTrial.id.id - val request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, s"/v1/trial/$id/$action", query)) - for { - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Trial](response) - } yield { - UpdateReply.Updated(reply) - } - } - - def start(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - singleAction(origTrial, "start") - - def submit(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - singleAction(origTrial, "submit") - - def restart(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - singleAction(origTrial, "restart") - - def flag(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - singleAction(origTrial, "flag") - - def resolve(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - singleAction(origTrial, "resolve") - - def archive(origTrial: Trial, comment: Option[String])( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - singleAction(origTrial, "archive", comment) - - def unassign(origTrial: Trial)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[UpdateReply] = - singleAction(origTrial, "unassign") - - override def addTrial(trial: TrialCreationRequest)( - implicit requestContext: AuthorizedServiceRequestContext[AuthUserInfo]): Future[Trial] = { - for { - entity <- Marshal(trial).to[RequestEntity] - request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, s"/v1/trial/${trial.nctId}")).withEntity(entity) - response <- transport.sendRequestGetResponse(requestContext)(request) - reply <- apiResponse[Trial](response) - } yield { - reply - } - } -} diff --git a/src/main/scala/xyz/driver/restquery/db/SlickPostgresQueryBuilder.scala b/src/main/scala/xyz/driver/restquery/db/SlickPostgresQueryBuilder.scala new file mode 100644 index 0000000..7038aa0 --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/db/SlickPostgresQueryBuilder.scala @@ -0,0 +1,116 @@ +package xyz.driver.pdsuicommon.db + +import java.time.{LocalDateTime, ZoneOffset} + +import org.slf4j.LoggerFactory +import slick.jdbc.{GetResult, JdbcProfile} +import xyz.driver.core.database.SlickDal + +import scala.collection.breakOut +import scala.concurrent.ExecutionContext + +object SlickPostgresQueryBuilder { + private val logger = LoggerFactory.getLogger(this.getClass) + + import xyz.driver.pdsuicommon.db.SlickQueryBuilder._ + + def apply[T](databaseName: String, + tableName: String, + lastUpdateFieldName: Option[String], + nullableFields: Set[String], + links: Set[SlickTableLink], + runner: Runner[T], + countRunner: CountRunner)(implicit sqlContext: SlickDal, + profile: JdbcProfile, + getResult: GetResult[T], + ec: ExecutionContext): SlickPostgresQueryBuilder[T] = { + val parameters = SlickPostgresQueryBuilderParameters( + databaseName = databaseName, + tableData = TableData(tableName, lastUpdateFieldName, nullableFields), + links = links.map(x => x.foreignTableName -> x)(breakOut) + ) + new SlickPostgresQueryBuilder[T](parameters)(runner, countRunner) + } + + def apply[T](databaseName: String, + tableName: String, + lastUpdateFieldName: Option[String], + nullableFields: Set[String], + links: Set[SlickTableLink])(implicit sqlContext: SlickDal, + profile: JdbcProfile, + getResult: GetResult[T], + ec: ExecutionContext): SlickPostgresQueryBuilder[T] = { + apply[T](databaseName, + tableName, + SlickQueryBuilderParameters.AllFields, + lastUpdateFieldName, + nullableFields, + links) + } + + def apply[T](databaseName: String, + tableName: String, + fields: Set[String], + lastUpdateFieldName: Option[String], + nullableFields: Set[String], + links: Set[SlickTableLink])(implicit sqlContext: SlickDal, + profile: JdbcProfile, + getResult: GetResult[T], + ec: ExecutionContext): SlickPostgresQueryBuilder[T] = { + + val runner: Runner[T] = { parameters => + val sql = parameters.toSql(countQuery = false, fields = fields).as[T] + logger.debug(s"Built an SQL query: $sql") + sqlContext.execute(sql) + } + + val countRunner: CountRunner = { parameters => + implicit val getCountResult: GetResult[(Int, Option[LocalDateTime])] = GetResult({ r => + val count = r.rs.getInt(1) + val lastUpdate = if (parameters.tableData.lastUpdateFieldName.isDefined) { + Option(r.rs.getTimestamp(2)).map(timestampToLocalDateTime) + } else None + (count, lastUpdate) + }) + val sql = parameters.toSql(countQuery = true).as[(Int, Option[LocalDateTime])] + logger.debug(s"Built an SQL query returning count: $sql") + sqlContext.execute(sql).map(_.head) + } + + apply[T]( + databaseName = databaseName, + tableName = tableName, + lastUpdateFieldName = lastUpdateFieldName, + nullableFields = nullableFields, + links = links, + runner = runner, + countRunner = countRunner + ) + } + + def timestampToLocalDateTime(timestamp: java.sql.Timestamp): LocalDateTime = { + LocalDateTime.ofInstant(timestamp.toInstant, ZoneOffset.UTC) + } +} + +class SlickPostgresQueryBuilder[T](parameters: SlickPostgresQueryBuilderParameters)( + implicit runner: SlickQueryBuilder.Runner[T], + countRunner: SlickQueryBuilder.CountRunner) + extends SlickQueryBuilder[T](parameters) { + + def withFilter(newFilter: SearchFilterExpr): SlickQueryBuilder[T] = { + new SlickPostgresQueryBuilder[T](parameters.copy(filter = newFilter)) + } + + def withSorting(newSorting: Sorting): SlickQueryBuilder[T] = { + new SlickPostgresQueryBuilder[T](parameters.copy(sorting = newSorting)) + } + + def withPagination(newPagination: Pagination): SlickQueryBuilder[T] = { + new SlickPostgresQueryBuilder[T](parameters.copy(pagination = Some(newPagination))) + } + + def resetPagination: SlickQueryBuilder[T] = { + new SlickPostgresQueryBuilder[T](parameters.copy(pagination = None)) + } +} diff --git a/src/main/scala/xyz/driver/restquery/db/SlickQueryBuilder.scala b/src/main/scala/xyz/driver/restquery/db/SlickQueryBuilder.scala new file mode 100644 index 0000000..9962edf --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/db/SlickQueryBuilder.scala @@ -0,0 +1,387 @@ +package xyz.driver.pdsuicommon.db + +import java.sql.{JDBCType, PreparedStatement} +import java.time.LocalDateTime + +import slick.jdbc.{JdbcProfile, PositionedParameters, SQLActionBuilder, SetParameter} +import xyz.driver.pdsuicommon.db.Sorting.{Dimension, Sequential} +import xyz.driver.pdsuicommon.db.SortingOrder.{Ascending, Descending} +import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} + +import scala.concurrent.{ExecutionContext, Future} + +object SlickQueryBuilder { + + type Runner[T] = SlickQueryBuilderParameters => Future[Seq[T]] + + type CountResult = Future[(Int, Option[LocalDateTime])] + + type CountRunner = SlickQueryBuilderParameters => CountResult + + /** + * Binder for PreparedStatement + */ + type Binder = PreparedStatement => PreparedStatement + + final case class TableData(tableName: String, + lastUpdateFieldName: Option[String] = None, + nullableFields: Set[String] = Set.empty) + + val AllFields = Set("*") + + implicit class SQLActionBuilderConcat(a: SQLActionBuilder) { + def concat(b: SQLActionBuilder): SQLActionBuilder = { + SQLActionBuilder(a.queryParts ++ b.queryParts, new SetParameter[Unit] { + def apply(p: Unit, pp: PositionedParameters): Unit = { + a.unitPConv.apply(p, pp) + b.unitPConv.apply(p, pp) + } + }) + } + } + + implicit object SetQueryParameter extends SetParameter[AnyRef] { + def apply(v: AnyRef, pp: PositionedParameters) = { + pp.setObject(v, JDBCType.BINARY.getVendorTypeNumber) + } + } + + implicit def setLongIdQueryParameter[T]: SetParameter[LongId[T]] = SetParameter[LongId[T]] { (v, pp) => + pp.setLong(v.id) + } + + implicit def setStringIdQueryParameter[T]: SetParameter[StringId[T]] = SetParameter[StringId[T]] { (v, pp) => + pp.setString(v.id) + } + + implicit def setUuidIdQueryParameter[T]: SetParameter[UuidId[T]] = SetParameter[UuidId[T]] { (v, pp) => + pp.setObject(v.id, JDBCType.BINARY.getVendorTypeNumber) + } +} + +final case class SlickTableLink(keyColumnName: String, foreignTableName: String, foreignKeyColumnName: String) + +object SlickQueryBuilderParameters { + val AllFields = Set("*") +} + +sealed trait SlickQueryBuilderParameters { + import SlickQueryBuilder._ + + def databaseName: String + def tableData: SlickQueryBuilder.TableData + def links: Map[String, SlickTableLink] + def filter: SearchFilterExpr + def sorting: Sorting + def pagination: Option[Pagination] + + def qs: String + + def findLink(tableName: String): SlickTableLink = links.get(tableName) match { + case None => throw new IllegalArgumentException(s"Cannot find a link for `$tableName`") + case Some(link) => link + } + + def toSql(countQuery: Boolean = false)(implicit profile: JdbcProfile): SQLActionBuilder = { + toSql(countQuery, SlickQueryBuilderParameters.AllFields) + } + + def toSql(countQuery: Boolean, fields: Set[String])(implicit profile: JdbcProfile): SQLActionBuilder = { + import profile.api._ + val escapedTableName = s"""$qs$databaseName$qs.$qs${tableData.tableName}$qs""" + val fieldsSql: String = if (countQuery) { + val suffix: String = tableData.lastUpdateFieldName match { + case Some(lastUpdateField) => s", max($escapedTableName.$qs$lastUpdateField$qs)" + case None => "" + } + s"count(*) $suffix" + } else { + if (fields == SlickQueryBuilderParameters.AllFields) { + s"$escapedTableName.*" + } else { + fields + .map { field => + s"$escapedTableName.$qs$field$qs" + } + .mkString(", ") + } + } + val where = filterToSql(escapedTableName, filter) + val orderBy = sortingToSql(escapedTableName, sorting) + + val limitSql = limitToSql() + + val sql = sql"""select #$fieldsSql from #$escapedTableName""" + + val filtersTableLinks: Seq[SlickTableLink] = { + import SearchFilterExpr._ + def aux(expr: SearchFilterExpr): Seq[SlickTableLink] = expr match { + case Atom.TableName(tableName) => List(findLink(tableName)) + case Intersection(xs) => xs.flatMap(aux) + case Union(xs) => xs.flatMap(aux) + case _ => Nil + } + aux(filter) + } + + val sortingTableLinks: Seq[SlickTableLink] = Sorting.collect(sorting) { + case Dimension(Some(foreignTableName), _, _) => findLink(foreignTableName) + } + + // Combine links from sorting and filter without duplicates + val foreignTableLinks = (filtersTableLinks ++ sortingTableLinks).distinct + + def fkSql(fkLinksSql: SQLActionBuilder, tableLinks: Seq[SlickTableLink]): SQLActionBuilder = { + if (tableLinks.nonEmpty) { + tableLinks.head match { + case SlickTableLink(keyColumnName, foreignTableName, foreignKeyColumnName) => + val escapedForeignTableName = s"$qs$databaseName$qs.$qs$foreignTableName$qs" + val join = sql""" inner join #$escapedForeignTableName + on #$escapedTableName.#$qs#$keyColumnName#$qs=#$escapedForeignTableName.#$qs#$foreignKeyColumnName#$qs""" + fkSql(fkLinksSql concat join, tableLinks.tail) + } + } else fkLinksSql + } + val foreignTableLinksSql = fkSql(sql"", foreignTableLinks) + + val whereSql = if (where.queryParts.size > 1) { + sql" where " concat where + } else sql"" + + val orderSql = if (orderBy.nonEmpty && !countQuery) { + sql" order by #$orderBy" + } else sql"" + + val limSql = if (limitSql.queryParts.size > 1 && !countQuery) { + sql" " concat limitSql + } else sql"" + + sql concat foreignTableLinksSql concat whereSql concat orderSql concat limSql + } + + /** + * Converts filter expression to SQL expression. + * + * @return Returns SQL string and list of values for binding in prepared statement. + */ + protected def filterToSql(escapedTableName: String, filter: SearchFilterExpr)( + implicit profile: JdbcProfile): SQLActionBuilder = { + import SearchFilterBinaryOperation._ + import SearchFilterExpr._ + import profile.api._ + + def isNull(string: AnyRef) = Option(string).isEmpty || string.toString.toLowerCase == "null" + + def escapeDimension(dimension: SearchFilterExpr.Dimension) = { + s"${dimension.tableName.map(t => s"$qs$databaseName$qs.$qs$t$qs").getOrElse(escapedTableName)}.$qs${dimension.name}$qs" + } + + def filterToSqlMultiple(operands: Seq[SearchFilterExpr]) = operands.collect { + case x if !SearchFilterExpr.isEmpty(x) => filterToSql(escapedTableName, x) + } + + def multipleSqlToAction(first: Boolean, + op: String, + conditions: Seq[SQLActionBuilder], + sql: SQLActionBuilder): SQLActionBuilder = { + if (conditions.nonEmpty) { + val condition = conditions.head + if (first) { + multipleSqlToAction(first = false, op, conditions.tail, condition) + } else { + multipleSqlToAction(first = false, op, conditions.tail, sql concat sql" #${op} " concat condition) + } + } else sql + } + + def concatenateParameters(sql: SQLActionBuilder, first: Boolean, tail: Seq[AnyRef]): SQLActionBuilder = { + if (tail.nonEmpty) { + if (!first) { + concatenateParameters(sql concat sql""",${tail.head}""", first = false, tail.tail) + } else { + concatenateParameters(sql"""(${tail.head}""", first = false, tail.tail) + } + } else sql concat sql")" + } + + filter match { + case x if isEmpty(x) => + sql"" + + case AllowAll => + sql"1=1" + + case DenyAll => + sql"1=0" + + case Atom.Binary(dimension, Eq, value) if isNull(value) => + sql"#${escapeDimension(dimension)} is NULL" + + case Atom.Binary(dimension, NotEq, value) if isNull(value) => + sql"#${escapeDimension(dimension)} is not NULL" + + case Atom.Binary(dimension, NotEq, value) if tableData.nullableFields.contains(dimension.name) => + // In MySQL NULL <> Any === NULL + // So, to handle NotEq for nullable fields we need to use more complex SQL expression. + // http://dev.mysql.com/doc/refman/5.7/en/working-with-null.html + val escapedColumn = escapeDimension(dimension) + sql"(#${escapedColumn} is null or #${escapedColumn} != $value)" + + case Atom.Binary(dimension, op, value) => + val operator = op match { + case Eq => sql"=" + case NotEq => sql"!=" + case Like => sql" like " + case Gt => sql">" + case GtEq => sql">=" + case Lt => sql"<" + case LtEq => sql"<=" + } + sql"#${escapeDimension(dimension)}" concat operator concat sql"""$value""" + + case Atom.NAry(dimension, op, values) => + val sqlOp = op match { + case SearchFilterNAryOperation.In => sql" in " + case SearchFilterNAryOperation.NotIn => sql" not in " + } + + if (values.nonEmpty) { + val formattedValues = concatenateParameters(sql"", first = true, values) + sql"#${escapeDimension(dimension)}" concat sqlOp concat formattedValues + } else { + sql"1=0" + } + + case Intersection(operands) => + val filter = multipleSqlToAction(first = true, "and", filterToSqlMultiple(operands), sql"") + sql"(" concat filter concat sql")" + + case Union(operands) => + val filter = multipleSqlToAction(first = true, "or", filterToSqlMultiple(operands), sql"") + sql"(" concat filter concat sql")" + } + } + + protected def limitToSql()(implicit profile: JdbcProfile): SQLActionBuilder + + /** + * @param escapedMainTableName Should be escaped + */ + protected def sortingToSql(escapedMainTableName: String, sorting: Sorting)(implicit profile: JdbcProfile): String = { + sorting match { + case Dimension(optSortingTableName, field, order) => + val sortingTableName = + optSortingTableName.map(x => s"$qs$databaseName$qs.$qs$x$qs").getOrElse(escapedMainTableName) + val fullName = s"$sortingTableName.$qs$field$qs" + + s"$fullName ${orderToSql(order)}" + + case Sequential(xs) => + xs.map(sortingToSql(escapedMainTableName, _)).mkString(", ") + } + } + + protected def orderToSql(x: SortingOrder): String = x match { + case Ascending => "asc" + case Descending => "desc" + } + + protected def binder(bindings: List[AnyRef])(bind: PreparedStatement): PreparedStatement = { + bindings.zipWithIndex.foreach { + case (binding, index) => + bind.setObject(index + 1, binding) + } + + bind + } + +} + +final case class SlickPostgresQueryBuilderParameters(databaseName: String, + tableData: SlickQueryBuilder.TableData, + links: Map[String, SlickTableLink] = Map.empty, + filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Sorting = Sorting.Empty, + pagination: Option[Pagination] = None) + extends SlickQueryBuilderParameters { + + def limitToSql()(implicit profile: JdbcProfile): SQLActionBuilder = { + import profile.api._ + pagination.map { pagination => + val startFrom = (pagination.pageNumber - 1) * pagination.pageSize + sql"limit #${pagination.pageSize} OFFSET #$startFrom" + } getOrElse (sql"") + } + + val qs = """"""" + +} + +/** + * @param links Links to another tables grouped by foreignTableName + */ +final case class SlickMysqlQueryBuilderParameters(databaseName: String, + tableData: SlickQueryBuilder.TableData, + links: Map[String, SlickTableLink] = Map.empty, + filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Sorting = Sorting.Empty, + pagination: Option[Pagination] = None) + extends SlickQueryBuilderParameters { + + def limitToSql()(implicit profile: JdbcProfile): SQLActionBuilder = { + import profile.api._ + pagination + .map { pagination => + val startFrom = (pagination.pageNumber - 1) * pagination.pageSize + sql"limit #$startFrom, #${pagination.pageSize}" + } + .getOrElse(sql"") + } + + val qs = """`""" + +} + +abstract class SlickQueryBuilder[T](val parameters: SlickQueryBuilderParameters)( + implicit runner: SlickQueryBuilder.Runner[T], + countRunner: SlickQueryBuilder.CountRunner) { + + def run()(implicit ec: ExecutionContext): Future[Seq[T]] = runner(parameters) + + def runCount()(implicit ec: ExecutionContext): SlickQueryBuilder.CountResult = countRunner(parameters) + + /** + * Runs the query and returns total found rows without considering of pagination. + */ + def runWithCount()(implicit ec: ExecutionContext): Future[(Seq[T], Int, Option[LocalDateTime])] = { + for { + all <- run + (total, lastUpdate) <- runCount + } yield (all, total, lastUpdate) + } + + def withFilter(newFilter: SearchFilterExpr): SlickQueryBuilder[T] + + def withFilter(filter: Option[SearchFilterExpr]): SlickQueryBuilder[T] = { + filter.fold(this)(withFilter) + } + + def resetFilter: SlickQueryBuilder[T] = withFilter(SearchFilterExpr.Empty) + + def withSorting(newSorting: Sorting): SlickQueryBuilder[T] + + def withSorting(sorting: Option[Sorting]): SlickQueryBuilder[T] = { + sorting.fold(this)(withSorting) + } + + def resetSorting: SlickQueryBuilder[T] = withSorting(Sorting.Empty) + + def withPagination(newPagination: Pagination): SlickQueryBuilder[T] + + def withPagination(pagination: Option[Pagination]): SlickQueryBuilder[T] = { + pagination.fold(this)(withPagination) + } + + def resetPagination: SlickQueryBuilder[T] + +} diff --git a/src/main/scala/xyz/driver/restquery/db/SlickQueryBuilderParameters.scala b/src/main/scala/xyz/driver/restquery/db/SlickQueryBuilderParameters.scala new file mode 100644 index 0000000..6ab7eb4 --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/db/SlickQueryBuilderParameters.scala @@ -0,0 +1,240 @@ +package xyz.driver.restquery.query + +import java.sql.PreparedStatement + +import slick.jdbc.{JdbcProfile, SQLActionBuilder} +import xyz.driver.restquery.db.{SlickQueryBuilder, SlickQueryBuilderParameters, SlickTableLink} +import xyz.driver.restquery.query.Sorting.{Dimension, Sequential} +import xyz.driver.restquery.query.SortingOrder.{Ascending, Descending} + +trait SlickQueryBuilderParameters { + import SlickQueryBuilder._ + + def databaseName: String + def tableData: SlickQueryBuilder.TableData + def links: Map[String, SlickTableLink] + def filter: SearchFilterExpr + def sorting: Sorting + def pagination: Option[Pagination] + + def qs: String + + def findLink(tableName: String): SlickTableLink = links.get(tableName) match { + case None => throw new IllegalArgumentException(s"Cannot find a link for `$tableName`") + case Some(link) => link + } + + def toSql(countQuery: Boolean = false)(implicit profile: JdbcProfile): SQLActionBuilder = { + toSql(countQuery, SlickQueryBuilderParameters.AllFields) + } + + def toSql(countQuery: Boolean, fields: Set[String])(implicit profile: JdbcProfile): SQLActionBuilder = { + import profile.api._ + val escapedTableName = s"""$qs$databaseName$qs.$qs${tableData.tableName}$qs""" + val fieldsSql: String = if (countQuery) { + val suffix: String = tableData.lastUpdateFieldName match { + case Some(lastUpdateField) => s", max($escapedTableName.$qs$lastUpdateField$qs)" + case None => "" + } + s"count(*) $suffix" + } else { + if (fields == SlickQueryBuilderParameters.AllFields) { + s"$escapedTableName.*" + } else { + fields + .map { field => + s"$escapedTableName.$qs$field$qs" + } + .mkString(", ") + } + } + val where = filterToSql(escapedTableName, filter) + val orderBy = sortingToSql(escapedTableName, sorting) + + val limitSql = limitToSql() + + val sql = sql"""select #$fieldsSql from #$escapedTableName""" + + val filtersTableLinks: Seq[SlickTableLink] = { + import SearchFilterExpr._ + def aux(expr: SearchFilterExpr): Seq[SlickTableLink] = expr match { + case Atom.TableName(tableName) => List(findLink(tableName)) + case Intersection(xs) => xs.flatMap(aux) + case Union(xs) => xs.flatMap(aux) + case _ => Nil + } + aux(filter) + } + + val sortingTableLinks: Seq[SlickTableLink] = Sorting.collect(sorting) { + case Dimension(Some(foreignTableName), _, _) => findLink(foreignTableName) + } + + // Combine links from sorting and filter without duplicates + val foreignTableLinks = (filtersTableLinks ++ sortingTableLinks).distinct + + def fkSql(fkLinksSql: SQLActionBuilder, tableLinks: Seq[SlickTableLink]): SQLActionBuilder = { + if (tableLinks.nonEmpty) { + tableLinks.head match { + case SlickTableLink(keyColumnName, foreignTableName, foreignKeyColumnName) => + val escapedForeignTableName = s"$qs$databaseName$qs.$qs$foreignTableName$qs" + val join = sql""" inner join #$escapedForeignTableName + on #$escapedTableName.#$qs#$keyColumnName#$qs=#$escapedForeignTableName.#$qs#$foreignKeyColumnName#$qs""" + fkSql(fkLinksSql concat join, tableLinks.tail) + } + } else fkLinksSql + } + val foreignTableLinksSql = fkSql(sql"", foreignTableLinks) + + val whereSql = if (where.queryParts.size > 1) { + sql" where " concat where + } else sql"" + + val orderSql = if (orderBy.nonEmpty && !countQuery) { + sql" order by #$orderBy" + } else sql"" + + val limSql = if (limitSql.queryParts.size > 1 && !countQuery) { + sql" " concat limitSql + } else sql"" + + sql concat foreignTableLinksSql concat whereSql concat orderSql concat limSql + } + + /** + * Converts filter expression to SQL expression. + * + * @return Returns SQL string and list of values for binding in prepared statement. + */ + protected def filterToSql(escapedTableName: String, filter: SearchFilterExpr)( + implicit profile: JdbcProfile): SQLActionBuilder = { + import SearchFilterBinaryOperation._ + import SearchFilterExpr._ + import profile.api._ + + def isNull(string: AnyRef) = Option(string).isEmpty || string.toString.toLowerCase == "null" + + def escapeDimension(dimension: SearchFilterExpr.Dimension) = { + s"${dimension.tableName.map(t => s"$qs$databaseName$qs.$qs$t$qs").getOrElse(escapedTableName)}.$qs${dimension.name}$qs" + } + + def filterToSqlMultiple(operands: Seq[SearchFilterExpr]) = operands.collect { + case x if !SearchFilterExpr.isEmpty(x) => filterToSql(escapedTableName, x) + } + + def multipleSqlToAction(first: Boolean, + op: String, + conditions: Seq[SQLActionBuilder], + sql: SQLActionBuilder): SQLActionBuilder = { + if (conditions.nonEmpty) { + val condition = conditions.head + if (first) { + multipleSqlToAction(first = false, op, conditions.tail, condition) + } else { + multipleSqlToAction(first = false, op, conditions.tail, sql concat sql" #${op} " concat condition) + } + } else sql + } + + def concatenateParameters(sql: SQLActionBuilder, first: Boolean, tail: Seq[AnyRef]): SQLActionBuilder = { + if (tail.nonEmpty) { + if (!first) { + concatenateParameters(sql concat sql""",${tail.head}""", first = false, tail.tail) + } else { + concatenateParameters(sql"""(${tail.head}""", first = false, tail.tail) + } + } else sql concat sql")" + } + + filter match { + case x if isEmpty(x) => + sql"" + + case AllowAll => + sql"1=1" + + case DenyAll => + sql"1=0" + + case Atom.Binary(dimension, Eq, value) if isNull(value) => + sql"#${escapeDimension(dimension)} is NULL" + + case Atom.Binary(dimension, NotEq, value) if isNull(value) => + sql"#${escapeDimension(dimension)} is not NULL" + + case Atom.Binary(dimension, NotEq, value) if tableData.nullableFields.contains(dimension.name) => + // In MySQL NULL <> Any === NULL + // So, to handle NotEq for nullable fields we need to use more complex SQL expression. + // http://dev.mysql.com/doc/refman/5.7/en/working-with-null.html + val escapedColumn = escapeDimension(dimension) + sql"(#${escapedColumn} is null or #${escapedColumn} != $value)" + + case Atom.Binary(dimension, op, value) => + val operator = op match { + case Eq => sql"=" + case NotEq => sql"!=" + case Like => sql" like " + case Gt => sql">" + case GtEq => sql">=" + case Lt => sql"<" + case LtEq => sql"<=" + } + sql"#${escapeDimension(dimension)}" concat operator concat sql"""$value""" + + case Atom.NAry(dimension, op, values) => + val sqlOp = op match { + case SearchFilterNAryOperation.In => sql" in " + case SearchFilterNAryOperation.NotIn => sql" not in " + } + + if (values.nonEmpty) { + val formattedValues = concatenateParameters(sql"", first = true, values) + sql"#${escapeDimension(dimension)}" concat sqlOp concat formattedValues + } else { + sql"1=0" + } + + case Intersection(operands) => + val filter = multipleSqlToAction(first = true, "and", filterToSqlMultiple(operands), sql"") + sql"(" concat filter concat sql")" + + case Union(operands) => + val filter = multipleSqlToAction(first = true, "or", filterToSqlMultiple(operands), sql"") + sql"(" concat filter concat sql")" + } + } + + protected def limitToSql()(implicit profile: JdbcProfile): SQLActionBuilder + + /** + * @param escapedMainTableName Should be escaped + */ + protected def sortingToSql(escapedMainTableName: String, sorting: Sorting)(implicit profile: JdbcProfile): String = { + sorting match { + case Dimension(optSortingTableName, field, order) => + val sortingTableName = + optSortingTableName.map(x => s"$qs$databaseName$qs.$qs$x$qs").getOrElse(escapedMainTableName) + val fullName = s"$sortingTableName.$qs$field$qs" + + s"$fullName ${orderToSql(order)}" + + case Sequential(xs) => + xs.map(sortingToSql(escapedMainTableName, _)).mkString(", ") + } + } + + protected def orderToSql(x: SortingOrder): String = x match { + case Ascending => "asc" + case Descending => "desc" + } + + protected def binder(bindings: List[AnyRef])(bind: PreparedStatement): PreparedStatement = { + bindings.zipWithIndex.foreach { + case (binding, index) => + bind.setObject(index + 1, binding) + } + + bind + } + +} diff --git a/src/main/scala/xyz/driver/restquery/query/Pagination.scala b/src/main/scala/xyz/driver/restquery/query/Pagination.scala new file mode 100644 index 0000000..27b8f12 --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/query/Pagination.scala @@ -0,0 +1,12 @@ +package xyz.driver.restquery.domain + +/** + * @param pageNumber Starts with 1 + */ +final case class Pagination(pageSize: Int, pageNumber: Int) + +object Pagination { + + // @see https://driverinc.atlassian.net/wiki/display/RA/REST+API+Specification#RESTAPISpecification-CommonRequestQueryParametersForWebServices + val Default = Pagination(pageSize = 100, pageNumber = 1) +} diff --git a/src/main/scala/xyz/driver/restquery/query/SearchFilterBinaryOperation.scala b/src/main/scala/xyz/driver/restquery/query/SearchFilterBinaryOperation.scala new file mode 100644 index 0000000..dab466b --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/query/SearchFilterBinaryOperation.scala @@ -0,0 +1,5 @@ +package xyz.driver.restquery.query + +class SearchFilterBinaryOperation { + +} diff --git a/src/main/scala/xyz/driver/restquery/query/SearchFilterExpr.scala b/src/main/scala/xyz/driver/restquery/query/SearchFilterExpr.scala new file mode 100644 index 0000000..6d2cb9a --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/query/SearchFilterExpr.scala @@ -0,0 +1,196 @@ +package xyz.driver.restquery.domain + +sealed trait SearchFilterExpr { + def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] + def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr +} + +object SearchFilterExpr { + + val Empty: Intersection = Intersection.Empty + val Forbid = Atom.Binary( + dimension = Dimension(None, "true"), + op = SearchFilterBinaryOperation.Eq, + value = "false" + ) + + final case class Dimension(tableName: Option[String], name: String) { + def isForeign: Boolean = tableName.isDefined + } + + sealed trait Atom extends SearchFilterExpr { + override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { + Some(this).filter(p) + } + + override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { + if (f.isDefinedAt(this)) f(this) + else this + } + } + + object Atom { + final case class Binary(dimension: Dimension, op: SearchFilterBinaryOperation, value: AnyRef) extends Atom + object Binary { + def apply(field: String, op: SearchFilterBinaryOperation, value: AnyRef): Binary = + Binary(Dimension(None, field), op, value) + } + + final case class NAry(dimension: Dimension, op: SearchFilterNAryOperation, values: Seq[AnyRef]) extends Atom + object NAry { + def apply(field: String, op: SearchFilterNAryOperation, values: Seq[AnyRef]): NAry = + NAry(Dimension(None, field), op, values) + } + + /** dimension.tableName extractor */ + object TableName { + def unapply(value: Atom): Option[String] = value match { + case Binary(Dimension(tableNameOpt, _), _, _) => tableNameOpt + case NAry(Dimension(tableNameOpt, _), _, _) => tableNameOpt + } + } + } + + final case class Intersection private (operands: Seq[SearchFilterExpr]) + extends SearchFilterExpr with SearchFilterExprSeqOps { + + override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { + if (f.isDefinedAt(this)) f(this) + else { + this.copy(operands.map(_.replace(f))) + } + } + + } + + object Intersection { + + val Empty = Intersection(Seq()) + + def create(operands: SearchFilterExpr*): SearchFilterExpr = { + val filtered = operands.filterNot(SearchFilterExpr.isEmpty) + filtered.size match { + case 0 => Empty + case 1 => filtered.head + case _ => Intersection(filtered) + } + } + } + + final case class Union private (operands: Seq[SearchFilterExpr]) + extends SearchFilterExpr with SearchFilterExprSeqOps { + + override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { + if (f.isDefinedAt(this)) f(this) + else { + this.copy(operands.map(_.replace(f))) + } + } + + } + + object Union { + + val Empty = Union(Seq()) + + def create(operands: SearchFilterExpr*): SearchFilterExpr = { + val filtered = operands.filterNot(SearchFilterExpr.isEmpty) + filtered.size match { + case 0 => Empty + case 1 => filtered.head + case _ => Union(filtered) + } + } + + def create(dimension: Dimension, values: String*): SearchFilterExpr = values.size match { + case 0 => SearchFilterExpr.Empty + case 1 => SearchFilterExpr.Atom.Binary(dimension, SearchFilterBinaryOperation.Eq, values.head) + case _ => + val filters = values.map { value => + SearchFilterExpr.Atom.Binary(dimension, SearchFilterBinaryOperation.Eq, value) + } + + create(filters: _*) + } + + def create(dimension: Dimension, values: Set[String]): SearchFilterExpr = + create(dimension, values.toSeq: _*) + + // Backwards compatible API + + /** Create SearchFilterExpr with empty tableName */ + def create(field: String, values: String*): SearchFilterExpr = + create(Dimension(None, field), values: _*) + + /** Create SearchFilterExpr with empty tableName */ + def create(field: String, values: Set[String]): SearchFilterExpr = + create(Dimension(None, field), values) + } + + case object AllowAll extends SearchFilterExpr { + override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { + Some(this).filter(p) + } + + override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { + if (f.isDefinedAt(this)) f(this) + else this + } + } + + case object DenyAll extends SearchFilterExpr { + override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { + Some(this).filter(p) + } + + override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { + if (f.isDefinedAt(this)) f(this) + else this + } + } + + def isEmpty(expr: SearchFilterExpr): Boolean = { + expr == Intersection.Empty || expr == Union.Empty + } + + sealed trait SearchFilterExprSeqOps { this: SearchFilterExpr => + + val operands: Seq[SearchFilterExpr] + + override def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] = { + if (p(this)) Some(this) + else { + // Search the first expr among operands, which satisfy p + // Is's ok to use foldLeft. If there will be performance issues, replace it by recursive loop + operands.foldLeft(Option.empty[SearchFilterExpr]) { + case (None, expr) => expr.find(p) + case (x, _) => x + } + } + } + } + +} + +sealed trait SearchFilterBinaryOperation + +object SearchFilterBinaryOperation { + + case object Eq extends SearchFilterBinaryOperation + case object NotEq extends SearchFilterBinaryOperation + case object Like extends SearchFilterBinaryOperation + case object Gt extends SearchFilterBinaryOperation + case object GtEq extends SearchFilterBinaryOperation + case object Lt extends SearchFilterBinaryOperation + case object LtEq extends SearchFilterBinaryOperation + +} + +sealed trait SearchFilterNAryOperation + +object SearchFilterNAryOperation { + + case object In extends SearchFilterNAryOperation + case object NotIn extends SearchFilterNAryOperation + +} diff --git a/src/main/scala/xyz/driver/restquery/query/SearchFilterNAryOperation.scala b/src/main/scala/xyz/driver/restquery/query/SearchFilterNAryOperation.scala new file mode 100644 index 0000000..0604c8f --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/query/SearchFilterNAryOperation.scala @@ -0,0 +1,5 @@ +package xyz.driver.restquery.query + +class SearchFilterNAryOperation { + +} diff --git a/src/main/scala/xyz/driver/restquery/query/Sorting.scala b/src/main/scala/xyz/driver/restquery/query/Sorting.scala new file mode 100644 index 0000000..e2642ad --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/query/Sorting.scala @@ -0,0 +1,56 @@ +package xyz.driver.restquery.domain + +import scala.collection.generic.CanBuildFrom + +sealed trait SortingOrder +object SortingOrder { + + case object Ascending extends SortingOrder + case object Descending extends SortingOrder + +} + +sealed trait Sorting + +object Sorting { + + val Empty = Sequential(Seq.empty) + + /** + * @param tableName None if the table is default (same) + * @param name Dimension name + * @param order Order + */ + final case class Dimension(tableName: Option[String], name: String, order: SortingOrder) extends Sorting { + def isForeign: Boolean = tableName.isDefined + } + + final case class Sequential(sorting: Seq[Dimension]) extends Sorting { + override def toString: String = if (isEmpty(this)) "Empty" else super.toString + } + + def isEmpty(input: Sorting): Boolean = { + input match { + case Sequential(Seq()) => true + case _ => false + } + } + + def filter(sorting: Sorting, p: Dimension => Boolean): Seq[Dimension] = sorting match { + case x: Dimension if p(x) => Seq(x) + case _: Dimension => Seq.empty + case Sequential(xs) => xs.filter(p) + } + + def collect[B, That](sorting: Sorting)(f: PartialFunction[Dimension, B])( + implicit bf: CanBuildFrom[Seq[Dimension], B, That]): That = sorting match { + case x: Dimension if f.isDefinedAt(x) => + val r = bf.apply() + r += f(x) + r.result() + + case _: Dimension => bf.apply().result() + case Sequential(xs) => xs.collect(f) + } + +} diff --git a/src/main/scala/xyz/driver/restquery/rest/Directives.scala b/src/main/scala/xyz/driver/restquery/rest/Directives.scala new file mode 100644 index 0000000..2936f70 --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/rest/Directives.scala @@ -0,0 +1,55 @@ +package xyz.driver.restquery.http + +import akka.http.scaladsl.server.Directives._ +import akka.http.scaladsl.server._ +import xyz.driver.restquery.domain.{SearchFilterExpr, _} +import xyz.driver.restquery.http.parsers._ + +import scala.util._ + +trait Directives { + + val paginated: Directive1[Pagination] = parameterSeq.flatMap { params => + PaginationParser.parse(params) match { + case Success(pagination) => provide(pagination) + case Failure(ex) => + reject(ValidationRejection("invalid pagination parameter", Some(ex))) + } + } + + def sorted(validDimensions: Set[String] = Set.empty): Directive1[Sorting] = parameterSeq.flatMap { params => + SortingParser.parse(validDimensions, params) match { + case Success(sorting) => provide(sorting) + case Failure(ex) => + reject(ValidationRejection("invalid sorting parameter", Some(ex))) + } + } + + val dimensioned: Directive1[Dimensions] = parameterSeq.flatMap { params => + DimensionsParser.tryParse(params) match { + case Success(dims) => provide(dims) + case Failure(ex) => + reject(ValidationRejection("invalid dimension parameter", Some(ex))) + } + } + + val searchFiltered: Directive1[SearchFilterExpr] = parameterSeq.flatMap { params => + SearchFilterParser.parse(params) match { + case Success(sorting) => provide(sorting) + case Failure(ex) => + reject(ValidationRejection("invalid filter parameter", Some(ex))) + } + } + + def StringIdInPath[T]: PathMatcher1[StringId[T]] = + PathMatchers.Segment.map((id) => StringId(id.toString)) + + def LongIdInPath[T]: PathMatcher1[LongId[T]] = + PathMatchers.LongNumber.map((id) => LongId(id)) + + def UuidIdInPath[T]: PathMatcher1[UuidId[T]] = + PathMatchers.JavaUUID.map((id) => UuidId(id)) + +} + +object Directives extends Directives diff --git a/src/main/scala/xyz/driver/restquery/rest/parsers/DimensionsParser.scala b/src/main/scala/xyz/driver/restquery/rest/parsers/DimensionsParser.scala new file mode 100644 index 0000000..7e139db --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/rest/parsers/DimensionsParser.scala @@ -0,0 +1,30 @@ +package xyz.driver.restquery.http.parsers + +import scala.util.{Failure, Success, Try} + +class Dimensions(private val xs: Set[String] = Set.empty) { + def contains(x: String): Boolean = xs.isEmpty || xs.contains(x) +} + +object DimensionsParser { + + @deprecated("play-akka transition", "0") + def tryParse(query: Map[String, Seq[String]]): Try[Dimensions] = + tryParse(query.toSeq.flatMap { + case (key, values) => + values.map(value => key -> value) + }) + + def tryParse(query: Seq[(String, String)]): Try[Dimensions] = { + query.collect { case ("dimensions", value) => value } match { + case Nil => Success(new Dimensions()) + + case x +: Nil => + val raw: Set[String] = x.split(",").view.map(_.trim).filter(_.nonEmpty).to[Set] + Success(new Dimensions(raw)) + + case xs => + Failure(new IllegalArgumentException(s"Dimensions are specified ${xs.size} times")) + } + } +} diff --git a/src/main/scala/xyz/driver/restquery/rest/parsers/PaginationParser.scala b/src/main/scala/xyz/driver/restquery/rest/parsers/PaginationParser.scala new file mode 100644 index 0000000..2b4547b --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/rest/parsers/PaginationParser.scala @@ -0,0 +1,23 @@ +package xyz.driver.restquery.http.parsers + +import xyz.driver.restquery.domain.Pagination + +import scala.util._ + +object PaginationParser { + + def parse(query: Seq[(String, String)]): Try[Pagination] = { + val IntString = """(\d+)""".r + def validate(field: String, default: Int) = query.collectFirst { case (`field`, size) => size } match { + case Some(IntString(x)) if x.toInt > 0 => x.toInt + case Some(IntString(x)) => throw new ParseQueryArgException((field, s"must greater than zero (found $x)")) + case Some(str) => throw new ParseQueryArgException((field, s"must be an integer (found $str)")) + case None => default + } + + Try { + Pagination(validate("pageSize", Pagination.Default.pageSize), + validate("pageNumber", Pagination.Default.pageNumber)) + } + } +} diff --git a/src/main/scala/xyz/driver/restquery/rest/parsers/ParseQueryArgException.scala b/src/main/scala/xyz/driver/restquery/rest/parsers/ParseQueryArgException.scala new file mode 100644 index 0000000..096c28f --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/rest/parsers/ParseQueryArgException.scala @@ -0,0 +1,3 @@ +package xyz.driver.restquery.http.parsers + +class ParseQueryArgException(val errors: (String, String)*) extends Exception(errors.mkString(",")) diff --git a/src/main/scala/xyz/driver/restquery/rest/parsers/SearchFilterParser.scala b/src/main/scala/xyz/driver/restquery/rest/parsers/SearchFilterParser.scala new file mode 100644 index 0000000..ce3009b --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/rest/parsers/SearchFilterParser.scala @@ -0,0 +1,178 @@ +package xyz.driver.restquery.http.parsers + +import java.util.UUID + +import fastparse.all._ +import fastparse.core.Parsed +import xyz.driver.restquery.domain.{SearchFilterBinaryOperation, SearchFilterExpr, SearchFilterNAryOperation} +import xyz.driver.restquery.utils.Utils +import xyz.driver.restquery.utils.Utils._ + +import scala.util.Try + +@SuppressWarnings(Array("org.wartremover.warts.Product", "org.wartremover.warts.Serializable")) +object SearchFilterParser { + + private object BinaryAtomFromTuple { + def unapply(input: (SearchFilterExpr.Dimension, (String, Any))): Option[SearchFilterExpr.Atom.Binary] = { + val (dimensionName, (strOperation, value)) = input + val updatedValue = trimIfString(value) + + parseOperation(strOperation.toLowerCase).map { op => + SearchFilterExpr.Atom.Binary(dimensionName, op, updatedValue.asInstanceOf[AnyRef]) + } + } + } + + private object NAryAtomFromTuple { + // Compiler warning: unchecked since it is eliminated by erasure, if we user Seq[String] + def unapply(input: (SearchFilterExpr.Dimension, (String, Seq[_]))): Option[SearchFilterExpr.Atom.NAry] = { + val (dimensionName, (strOperation, xs)) = input + val updatedValues = xs.map(trimIfString) + + if (strOperation.toLowerCase == "in") { + Some( + SearchFilterExpr.Atom + .NAry(dimensionName, SearchFilterNAryOperation.In, updatedValues.map(_.asInstanceOf[AnyRef]))) + } else { + None + } + } + } + + private def trimIfString(value: Any) = + value match { + case s: String => Utils.safeTrim(s) + case a => a + } + + private val operationsMapping = { + import xyz.driver.restquery.domain.SearchFilterBinaryOperation._ + + Map[String, SearchFilterBinaryOperation]( + "eq" -> Eq, + "noteq" -> NotEq, + "like" -> Like, + "gt" -> Gt, + "gteq" -> GtEq, + "lt" -> Lt, + "lteq" -> LtEq + ) + } + + private def parseOperation(x: String): Option[SearchFilterBinaryOperation] = operationsMapping.get(x) + + private val whitespaceParser = P(CharPred(Utils.isSafeWhitespace)) + + val dimensionParser: Parser[SearchFilterExpr.Dimension] = { + val identParser = P( + CharPred(c => c.isLetterOrDigit) + .rep(min = 1)).!.map(s => SearchFilterExpr.Dimension(None, toSnakeCase(s))) + val pathParser = P(identParser.! ~ "." ~ identParser.!) map { + case (left, right) => + SearchFilterExpr.Dimension(Some(toSnakeCase(left)), toSnakeCase(right)) + } + P(pathParser | identParser) + } + + private val commonOperatorParser: Parser[String] = { + P(IgnoreCase("eq") | IgnoreCase("like") | IgnoreCase("noteq")).! + } + + private val numericOperatorParser: Parser[String] = { + P(IgnoreCase("eq") | IgnoreCase("noteq") | ((IgnoreCase("gt") | IgnoreCase("lt")) ~ IgnoreCase("eq").?)).! + } + + private val naryOperatorParser: Parser[String] = P(IgnoreCase("in")).! + + private val isPositiveParser: Parser[Boolean] = P(CharIn("-+").!.?).map { + case Some("-") => false + case _ => true + } + + private val digitsParser: Parser[String] = P(CharIn('0' to '9').rep(min = 1).!) // Exclude Unicode "digits" + + private val numberParser: Parser[String] = P(isPositiveParser ~ digitsParser.! ~ ("." ~ digitsParser).!.?).map { + case (false, intPart, Some(fracPart)) => s"-$intPart.${fracPart.tail}" + case (false, intPart, None) => s"-$intPart" + case (_, intPart, Some(fracPart)) => s"$intPart.${fracPart.tail}" + case (_, intPart, None) => s"$intPart" + } + + private val nAryValueParser: Parser[String] = P(CharPred(_ != ',').rep(min = 1).!) + + private val longParser: Parser[Long] = P(CharIn('0' to '9').rep(min = 1).!.map(_.toLong)) + + private val booleanParser: Parser[Boolean] = + P((IgnoreCase("true") | IgnoreCase("false")).!.map(_.toBoolean)) + + private val hexDigit: Parser[String] = P((CharIn('a' to 'f') | CharIn('A' to 'F') | CharIn('0' to '9')).!) + + private val uuidParser: Parser[UUID] = + P( + hexDigit.rep(8).! ~ "-" ~ hexDigit.rep(4).! ~ "-" ~ hexDigit.rep(4).! ~ "-" ~ hexDigit.rep(4).! ~ "-" ~ hexDigit + .rep(12) + .!).map { + case (group1, group2, group3, group4, group5) => UUID.fromString(s"$group1-$group2-$group3-$group4-$group5") + } + + private val binaryAtomParser: Parser[SearchFilterExpr.Atom.Binary] = P( + dimensionParser ~ whitespaceParser ~ + ((numericOperatorParser.! ~ whitespaceParser ~ (longParser | numberParser.!) ~ End) | + (commonOperatorParser.! ~ whitespaceParser ~ (uuidParser | booleanParser | AnyChar.rep(min = 1).!) ~ End)) + ).map { + case BinaryAtomFromTuple(atom) => atom + } + + private val nAryAtomParser: Parser[SearchFilterExpr.Atom.NAry] = P( + dimensionParser ~ whitespaceParser ~ ( + naryOperatorParser ~ whitespaceParser ~ + ((longParser.rep(min = 1, sep = ",") ~ End) | (booleanParser.rep(min = 1, sep = ",") ~ End) | + (nAryValueParser.!.rep(min = 1, sep = ",") ~ End)) + ) + ).map { + case NAryAtomFromTuple(atom) => atom + } + + private val atomParser: Parser[SearchFilterExpr.Atom] = P(binaryAtomParser | nAryAtomParser) + + @deprecated("play-akka transition", "0") + def parse(query: Map[String, Seq[String]]): Try[SearchFilterExpr] = + parse(query.toSeq.flatMap { + case (key, values) => + values.map(value => key -> value) + }) + + def parse(query: Seq[(String, String)]): Try[SearchFilterExpr] = Try { + query.toList.collect { case ("filters", value) => value } match { + case Nil => SearchFilterExpr.Empty + + case head :: Nil => + atomParser.parse(head) match { + case Parsed.Success(x, _) => x + case e: Parsed.Failure[_, _] => throw new ParseQueryArgException("filters" -> formatFailure(1, e)) + } + + case xs => + val parsed = xs.map(x => atomParser.parse(x)) + val failures: Seq[String] = parsed.zipWithIndex.collect { + case (e: Parsed.Failure[_, _], index) => formatFailure(index, e) + } + + if (failures.isEmpty) { + val filters = parsed.collect { + case Parsed.Success(x, _) => x + } + + SearchFilterExpr.Intersection.create(filters: _*) + } else { + throw new ParseQueryArgException("filters" -> failures.mkString("; ")) + } + } + } + + private def formatFailure(sectionIndex: Int, e: Parsed.Failure[_, _]): String = { + s"section $sectionIndex: ${fastparse.core.ParseError.msg(e.extra.input, e.extra.traced.expected, e.index)}" + } + +} diff --git a/src/main/scala/xyz/driver/restquery/rest/parsers/SortingParser.scala b/src/main/scala/xyz/driver/restquery/rest/parsers/SortingParser.scala new file mode 100644 index 0000000..f2a3c04 --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/rest/parsers/SortingParser.scala @@ -0,0 +1,64 @@ +package xyz.driver.restquery.http.parsers + +import fastparse.all._ +import fastparse.core.Parsed +import xyz.driver.restquery.domain.{Sorting, SortingOrder} +import xyz.driver.restquery.utils.Utils._ + +import scala.util.Try + +object SortingParser { + + private val sortingOrderParser: Parser[SortingOrder] = P("-".!.?).map { + case Some(_) => SortingOrder.Descending + case None => SortingOrder.Ascending + } + + private def dimensionSortingParser(validDimensions: Seq[String]): Parser[Sorting.Dimension] = { + P(sortingOrderParser ~ StringIn(validDimensions: _*).!).map { + case (sortingOrder, field) => + val prefixedFields = field.split("\\.", 2) + prefixedFields.size match { + case 1 => Sorting.Dimension(None, toSnakeCase(field), sortingOrder) + case 2 => + Sorting.Dimension(Some(prefixedFields.head).map(toSnakeCase), + toSnakeCase(prefixedFields.last), + sortingOrder) + } + } + } + + private def sequentialSortingParser(validDimensions: Seq[String]): Parser[Sorting.Sequential] = { + P(dimensionSortingParser(validDimensions).rep(min = 1, sep = ",") ~ End).map { dimensions => + Sorting.Sequential(dimensions) + } + } + + @deprecated("play-akka transition", "0") + def parse(validDimensions: Set[String], query: Map[String, Seq[String]]): Try[Sorting] = + parse(validDimensions, query.toSeq.flatMap { + case (key, values) => + values.map(value => key -> value) + }) + + def parse(validDimensions: Set[String], query: Seq[(String, String)]): Try[Sorting] = Try { + query.toList.collect { case ("sort", value) => value } match { + case Nil => Sorting.Sequential(Seq.empty) + + case rawSorting :: Nil => + val parser = sequentialSortingParser(validDimensions.toSeq) + parser.parse(rawSorting) match { + case Parsed.Success(x, _) => x + case e: Parsed.Failure[_, _] => + throw new ParseQueryArgException("sort" -> formatFailure(e)) + } + + case _ => throw new ParseQueryArgException("sort" -> "multiple sections are not allowed") + } + } + + private def formatFailure(e: Parsed.Failure[_, _]): String = { + fastparse.core.ParseError.msg(e.extra.input, e.extra.traced.expected, e.index) + } + +} diff --git a/src/main/scala/xyz/driver/restquery/utils/Utils.scala b/src/main/scala/xyz/driver/restquery/utils/Utils.scala new file mode 100644 index 0000000..86c65d7 --- /dev/null +++ b/src/main/scala/xyz/driver/restquery/utils/Utils.scala @@ -0,0 +1,79 @@ +package xyz.driver.pdsuicommon.utils + +import java.time.LocalDateTime +import java.util.regex.{Matcher, Pattern} + +object Utils { + + implicit val localDateTimeOrdering: Ordering[LocalDateTime] = Ordering.fromLessThan(_ isBefore _) + + /** + * Hack to avoid scala compiler bug with getSimpleName + * @see https://issues.scala-lang.org/browse/SI-2034 + */ + def getClassSimpleName(klass: Class[_]): String = { + try { + klass.getSimpleName + } catch { + case _: InternalError => + val fullName = klass.getName.stripSuffix("$") + val fullClassName = fullName.substring(fullName.lastIndexOf(".") + 1) + fullClassName.substring(fullClassName.lastIndexOf("$") + 1) + } + } + + def toSnakeCase(str: String): String = + str + .replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2") + .replaceAll("([a-z\\d])([A-Z])", "$1_$2") + .toLowerCase + + def toCamelCase(str: String): String = { + val sb = new StringBuffer() + def loop(m: Matcher): Unit = if (m.find()) { + m.appendReplacement(sb, m.group(1).toUpperCase()) + loop(m) + } + val m: Matcher = Pattern.compile("_(.)").matcher(str) + loop(m) + m.appendTail(sb) + sb.toString + } + + object Whitespace { + private val Table: String = + "\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000" + + "\u2029\u000B\u3000\u2008\u2003\u205F\u3000\u1680" + + "\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009" + + "\u3000\u2004\u3000\u3000\u2028\n\u2007\u3000" + + private val Multiplier: Int = 1682554634 + private val Shift: Int = Integer.numberOfLeadingZeros(Table.length - 1) + + def matches(c: Char): Boolean = Table.charAt((Multiplier * c) >>> Shift) == c + } + + def isSafeWhitespace(char: Char): Boolean = Whitespace.matches(char) + + // From Guava + def isSafeControl(char: Char): Boolean = + char <= '\u001f' || (char >= '\u007f' && char <= '\u009f') + + + def safeTrim(string: String): String = { + def shouldKeep(c: Char): Boolean = !isSafeControl(c) && !isSafeWhitespace(c) + + if (string.isEmpty) { + "" + } else { + val start = string.indexWhere(shouldKeep) + val end = string.lastIndexWhere(shouldKeep) + + if (start >= 0 && end >= 0) { + string.substring(start, end + 1) + } else { + "" + } + } + } +} diff --git a/src/test/scala/xyz/driver/pdsuicommon/db/SearchFilterExprSuite.scala b/src/test/scala/xyz/driver/pdsuicommon/db/SearchFilterExprSuite.scala deleted file mode 100644 index 35c8d30..0000000 --- a/src/test/scala/xyz/driver/pdsuicommon/db/SearchFilterExprSuite.scala +++ /dev/null @@ -1,34 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import org.scalatest.{FreeSpecLike, MustMatchers} - -class SearchFilterExprSuite extends FreeSpecLike with MustMatchers { - - "replace" - { - "all entities are changed" in { - val ast = SearchFilterExpr.Union( - Seq( - SearchFilterExpr.Intersection( - Seq( - SearchFilterExpr.Atom.Binary("foo", SearchFilterBinaryOperation.Gt, "10"), - SearchFilterExpr.Atom.Binary("foo", SearchFilterBinaryOperation.Lt, "20") - )), - SearchFilterExpr.Atom.NAry("bar", SearchFilterNAryOperation.In, Seq("x", "y", "z")), - SearchFilterExpr.Atom.Binary("foo", SearchFilterBinaryOperation.Eq, "40") - )) - - val newAst = ast.replace { - case x: SearchFilterExpr.Atom.Binary if x.dimension.name == "foo" => - x.copy(dimension = x.dimension.copy(name = "bar")) - } - - val result = newAst.find { - case x: SearchFilterExpr.Atom.Binary => x.dimension.name == "foo" - case _ => false - } - - result mustBe empty - } - } - -} diff --git a/src/test/scala/xyz/driver/pdsuicommon/error/UnexpectedFilterException.scala b/src/test/scala/xyz/driver/pdsuicommon/error/UnexpectedFilterException.scala deleted file mode 100644 index 567661a..0000000 --- a/src/test/scala/xyz/driver/pdsuicommon/error/UnexpectedFilterException.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.pdsuicommon.error - -class UnexpectedFilterException(message: String) extends RuntimeException(message) diff --git a/src/test/scala/xyz/driver/pdsuicommon/logging/PhiStringContextSuite.scala b/src/test/scala/xyz/driver/pdsuicommon/logging/PhiStringContextSuite.scala deleted file mode 100644 index 8fd783f..0000000 --- a/src/test/scala/xyz/driver/pdsuicommon/logging/PhiStringContextSuite.scala +++ /dev/null @@ -1,31 +0,0 @@ -package xyz.driver.pdsuicommon.logging - -import org.scalatest.FreeSpecLike - -class PhiStringContextSuite extends FreeSpecLike { - - case class Foo(x: Int, y: String) { - val z: Boolean = true - } - - case class Bar(y: Boolean) - - implicit def fooToPhiString(foo: Foo): PhiString = new PhiString(s"Foo(z=${foo.z})") - - "should not compile if there is no PhiString implicit" in assertDoesNotCompile( - """val bar = Bar(true) - |phi"bar is $bar"""".stripMargin - ) - - "should compile if there is a PhiString implicit" in assertCompiles( - """val foo = new Foo(1, "test") - |println(phi"foo is $foo}")""".stripMargin - ) - - "should not contain private info" in { - val foo = new Foo(42, "test") - val result = phi"foo is $foo".text - assert(!result.contains("test")) - assert(!result.contains("42")) - } -} diff --git a/src/test/scala/xyz/driver/pdsuicommon/parsers/PaginationParserSuite.scala b/src/test/scala/xyz/driver/pdsuicommon/parsers/PaginationParserSuite.scala deleted file mode 100644 index 609c8c8..0000000 --- a/src/test/scala/xyz/driver/pdsuicommon/parsers/PaginationParserSuite.scala +++ /dev/null @@ -1,103 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import xyz.driver.pdsuicommon.db.Pagination -import xyz.driver.pdsuicommon.parsers.TestUtils._ -import org.scalatest.{FreeSpecLike, MustMatchers} - -import scala.util.{Failure, Try} - -class PaginationParserSuite extends FreeSpecLike with MustMatchers { - - "parse" - { - "pageSize" - { - "should parse positive value" in { - val pagination = PaginationParser.parse( - Seq( - "pageSize" -> "10", - "pageNumber" -> "1" - )) - pagination must success - pagination.get.pageSize mustBe 10 - } - - "should return a default value if there is no one" in { - val pagination = PaginationParser.parse( - Seq( - "pageNumber" -> "1" - )) - pagination must success - pagination.get.pageSize mustBe 100 - } - - "should return a error for zero value" in { - val pagination = PaginationParser.parse( - Seq( - "pageSize" -> "0", - "pageNumber" -> "1" - )) - - checkFailedValidationOnlyOn(pagination, "pageSize") - } - - "should return a error for negative value" in { - val pagination = PaginationParser.parse( - Seq( - "pageSize" -> "-10", - "pageNumber" -> "1" - )) - - checkFailedValidationOnlyOn(pagination, "pageSize") - } - } - - "pageNumber" - { - "should parse positive value" in { - val pagination = PaginationParser.parse( - Seq( - "pageSize" -> "1", - "pageNumber" -> "1" - )) - pagination must success - pagination.get.pageSize mustBe 1 - } - - "should return a default value if there is no one" in { - val pagination = PaginationParser.parse( - Seq( - "pageSize" -> "1" - )) - pagination must success - pagination.get.pageNumber mustBe 1 - } - - "should return a error for zero value" in { - val pagination = PaginationParser.parse( - Seq( - "pageSize" -> "1", - "pageNumber" -> "0" - )) - - checkFailedValidationOnlyOn(pagination, "pageNumber") - } - - "should return a error for negative value" in { - val pagination = PaginationParser.parse( - Seq( - "pageSize" -> "1", - "pageNumber" -> "-1" - )) - - checkFailedValidationOnlyOn(pagination, "pageNumber") - } - } - } - - private def checkFailedValidationOnlyOn(pagination: Try[Pagination], key: String): Unit = { - pagination must failWith[ParseQueryArgException] - - val Failure(e: ParseQueryArgException) = pagination - e.errors.size mustBe 1 - e.errors.head._1 mustBe key - } - -} diff --git a/src/test/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParserSuite.scala b/src/test/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParserSuite.scala deleted file mode 100644 index 0209222..0000000 --- a/src/test/scala/xyz/driver/pdsuicommon/parsers/SearchFilterParserSuite.scala +++ /dev/null @@ -1,260 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import java.util.UUID - -import xyz.driver.pdsuicommon.db.SearchFilterExpr.Dimension -import xyz.driver.pdsuicommon.db.{SearchFilterBinaryOperation, SearchFilterExpr, SearchFilterNAryOperation} -import xyz.driver.pdsuicommon.utils.Implicits.toStringOps -import xyz.driver.pdsuicommon.parsers.TestUtils._ -import fastparse.core.Parsed -import org.scalacheck.Arbitrary.arbitrary -import org.scalacheck.{Gen, Prop} -import org.scalatest.FreeSpecLike -import org.scalatest.prop.Checkers -import xyz.driver.pdsuicommon.db.SearchFilterBinaryOperation.Eq -import xyz.driver.pdsuicommon.db.SearchFilterNAryOperation.In -import xyz.driver.pdsuicommon.utils.Utils -import xyz.driver.pdsuicommon.utils.Utils._ - -import scala.util._ - -object SearchFilterParserSuite { - - class UnexpectedSearchFilterExprException(x: SearchFilterExpr) extends Exception(s"unexpected $x") - -} - -class SearchFilterParserSuite extends FreeSpecLike with Checkers { - - import SearchFilterParserSuite._ - - "parse" - { - "should convert column names to snake case" in { - import SearchFilterBinaryOperation._ - - val filter = SearchFilterParser.parse( - Seq( - "filters" -> "status IN Summarized,ReviewCriteria,Flagged,Done", - "filters" -> "previousStatus NOTEQ New", - "filters" -> "previousStatus NOTEQ ReviewSummary" - )) - - assert( - filter === Success(SearchFilterExpr.Intersection(List( - SearchFilterExpr.Atom - .NAry(Dimension(None, "status"), In, Seq("Summarized", "ReviewCriteria", "Flagged", "Done")), - SearchFilterExpr.Atom.Binary(Dimension(None, "previous_status"), NotEq, "New"), - SearchFilterExpr.Atom.Binary(Dimension(None, "previous_status"), NotEq, "ReviewSummary") - )))) - } - "dimensions" - { - "with table name" in check { - val dimensionGen = { - for (left <- Gen.identifier; right <- Gen.identifier) - yield left -> right - } - Prop.forAllNoShrink(dimensionGen) { - case (left, right) => - val raw = s"$left.$right" - val l = toSnakeCase(left) - val r = toSnakeCase(right) - SearchFilterParser.dimensionParser.parse(raw) match { - case Parsed.Success(Dimension(Some(`l`), `r`), _) => true - case _ => false - } - } - } - "just with field name" in check { - Prop.forAllNoShrink(Gen.identifier) { s => - val databaseS = Utils.toSnakeCase(s) - SearchFilterParser.dimensionParser.parse(s) match { - case Parsed.Success(Dimension(None, `databaseS`), _) => true - case _ => false - } - } - } - } - "atoms" - { - "binary" - { - "common operators" - { - "should be parsed with text values" in check { - import SearchFilterBinaryOperation._ - - val testQueryGen = queryGen( - dimensionGen = Gen.identifier, - opGen = commonBinaryOpsGen, - valueGen = nonEmptyString - ) - - Prop.forAllNoShrink(testQueryGen) { query => - SearchFilterParser - .parse(Seq("filters" -> query)) - .map { - case SearchFilterExpr.Atom.Binary(_, Eq | NotEq | Like, _) => true - case x => throw new UnexpectedSearchFilterExprException(x) - } - .successProp - } - } - } - - "numeric operators" - { - "should not be parsed with text values" in check { - val testQueryGen = queryGen( - dimensionGen = Gen.identifier, - opGen = numericBinaryOpsGen, - valueGen = nonEmptyString.filter { s => - !s.matches("^\\d+$") - } - ) - - Prop.forAllNoShrink(testQueryGen) { query => - SearchFilterParser.parse(Seq("filters" -> query)).failureProp - } - } - } - - "actual recordId" - { - "should not be parsed with numeric values" in { - val filter = SearchFilterParser.parse(Seq("filters" -> "recordId EQ 1")) - assert(filter === Success(SearchFilterExpr.Atom.Binary(Dimension(None, "record_id"), Eq, Long.box(1)))) - } - } - - "actual isVisible boolean" - { - "should not be parsed with boolean values" in { - val filter = SearchFilterParser.parse(Seq("filters" -> "isVisible EQ true")) - assert(filter === Success(SearchFilterExpr.Atom.Binary(Dimension(None, "is_visible"), Eq, Boolean.box(true)))) - } - } - - "actual patientId uuid" - { - "should parse the full UUID as java.util.UUID type" in { - val filter = SearchFilterParser.parse(Seq("filters" -> "patientId EQ 4b4879f7-42b3-4b7c-a685-5c97d9e69e7c")) - assert(filter === Success(SearchFilterExpr.Atom.Binary( - Dimension(None, "patient_id"), Eq, UUID.fromString("4b4879f7-42b3-4b7c-a685-5c97d9e69e7c")))) - } - } - - "all operators" - { - "should be parsed with numeric values" in check { - val testQueryGen = queryGen( - dimensionGen = Gen.identifier, - opGen = allBinaryOpsGen, - valueGen = numericBinaryAtomValuesGen - ) - - Prop.forAllNoShrink(testQueryGen) { query => - SearchFilterParser - .parse(Seq("filters" -> query)) - .map { - case _: SearchFilterExpr.Atom.Binary => true - case x => throw new UnexpectedSearchFilterExprException(x) - } - .successProp - } - } - } - } - - "n-ary" - { - "actual record Ids" - { - "should not be parsed with text values" in { - val filter = SearchFilterParser.parse(Seq("filters" -> "id IN 1,5")) - filter match { - case Success(_) => () - case Failure(t) => t.printStackTrace() - } - assert( - filter === Success(SearchFilterExpr.Atom.NAry(Dimension(None, "id"), In, Seq(Long.box(1), Long.box(5))))) - } - } - - "in" in check { - val testQueryGen = queryGen( - dimensionGen = Gen.identifier, - opGen = Gen.const("in"), - valueGen = inValuesGen - ) - - Prop.forAllNoShrink(testQueryGen) { query => - SearchFilterParser - .parse(Seq("filters" -> query)) - .map { - case SearchFilterExpr.Atom.NAry(_, SearchFilterNAryOperation.In, _) => true - case x => throw new UnexpectedSearchFilterExprException(x) - } - .successProp - } - } - } - } - - "intersections" - { - "should be parsed" in check { - val commonAtomsGen = queryGen( - dimensionGen = Gen.identifier, - opGen = commonBinaryOpsGen, - valueGen = nonEmptyString - ) - - val numericAtomsGen = queryGen( - dimensionGen = Gen.identifier, - opGen = numericBinaryOpsGen, - valueGen = numericBinaryAtomValuesGen - ) - - val allAtomsGen = Gen.oneOf(commonAtomsGen, numericAtomsGen) - val intersectionsGen = Gen.choose(1, 3).flatMap { size => - Gen.containerOfN[Seq, String](size, allAtomsGen) - } - - Prop.forAllNoShrink(intersectionsGen) { queries => - SearchFilterParser.parse(queries.map(query => "filters" -> query)).successProp - } - } - } - } - - private val CommonBinaryOps = Seq("eq", "noteq", "like") - private val NumericBinaryOps = Seq("gt", "gteq", "lt", "lteq") - - private val allBinaryOpsGen: Gen[String] = - Gen.oneOf(CommonBinaryOps ++ NumericBinaryOps).flatMap(randomCapitalization) - private val commonBinaryOpsGen: Gen[String] = Gen.oneOf(CommonBinaryOps).flatMap(randomCapitalization) - private val numericBinaryOpsGen: Gen[String] = Gen.oneOf(NumericBinaryOps).flatMap(randomCapitalization) - - private val inValueCharsGen: Gen[Char] = arbitrary[Char].filter(_ != ',') - - private val nonEmptyString = arbitrary[String].filter { s => - !s.safeTrim.isEmpty - } - - private val numericBinaryAtomValuesGen: Gen[String] = arbitrary[Long].map(_.toString) - private val inValueGen: Gen[String] = { - Gen.nonEmptyContainerOf[Seq, Char](inValueCharsGen).map(_.mkString).filter(_.safeTrim.nonEmpty) - } - private val inValuesGen: Gen[String] = Gen.choose(1, 5).flatMap { size => - Gen.containerOfN[Seq, String](size, inValueGen).map(_.mkString(",")) - } - - private def queryGen(dimensionGen: Gen[String], opGen: Gen[String], valueGen: Gen[String]): Gen[String] = - for { - dimension <- dimensionGen - op <- opGen - value <- valueGen - } yield s"$dimension $op $value" - - private def randomCapitalization(input: String): Gen[String] = { - Gen.containerOfN[Seq, Boolean](input.length, arbitrary[Boolean]).map { capitalize => - input.view - .zip(capitalize) - .map { - case (currChar, true) => currChar.toUpper - case (currChar, false) => currChar - } - .mkString - } - } - -} diff --git a/src/test/scala/xyz/driver/pdsuicommon/parsers/SortingParserSuite.scala b/src/test/scala/xyz/driver/pdsuicommon/parsers/SortingParserSuite.scala deleted file mode 100644 index f34f8e1..0000000 --- a/src/test/scala/xyz/driver/pdsuicommon/parsers/SortingParserSuite.scala +++ /dev/null @@ -1,96 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import xyz.driver.pdsuicommon.parsers.TestUtils._ -import org.scalacheck.Arbitrary.arbitrary -import org.scalacheck.{Gen, Prop} -import org.scalatest.prop.Checkers -import org.scalatest.{FreeSpecLike, MustMatchers} - -class SortingParserSuite extends FreeSpecLike with MustMatchers with Checkers { - - "parse" - { - "single dimension" - commonTests(singleSortingQueryGen) - "multiple dimensions in one query" - commonTests(multipleSortingQueryGen) - "multiple queries" in { - val r = SortingParser.parse(Set("foo", "bar"), Seq("sort" -> "foo", "sort" -> "bar")) - r must failWith[ParseQueryArgException] - } - } - - private def commonTests(queryGen: Set[String] => Gen[String]): Unit = { - "valid" in check { - val inputGen: Gen[(Set[String], String)] = for { - validDimensions <- dimensionsGen - sorting <- queryGen(validDimensions) - } yield (validDimensions, sorting) - - Prop.forAllNoShrink(inputGen) { - case (validDimensions, query) => - SortingParser.parse(validDimensions, Seq("sort" -> query)).successProp - } - } - - "invalid" in check { - val inputGen: Gen[(Set[String], String)] = for { - validDimensions <- dimensionsGen - invalidDimensions <- dimensionsGen.filter { xs => - xs.intersect(validDimensions).isEmpty - } - sorting <- queryGen(invalidDimensions) - } yield (validDimensions, sorting) - - Prop.forAllNoShrink(inputGen) { - case (validDimensions, query) => - SortingParser.parse(validDimensions, Seq("sort" -> query)).failureProp - } - } - } - - private val dimensionsGen: Gen[Set[String]] = for { - unPrefixedSize <- Gen.choose(0, 3) - prefixedSize <- Gen.choose(0, 3) - if (unPrefixedSize + prefixedSize) > 0 - - unPrefixedDimensions <- Gen.containerOfN[Set, String](unPrefixedSize, Gen.identifier) - - prefixes <- Gen.containerOfN[Set, String](prefixedSize, Gen.identifier) - dimensions <- Gen.containerOfN[Set, String](prefixedSize, Gen.identifier) - } yield { - val prefixedDimensions = prefixes.zip(dimensions).map { - case (prefix, dimension) => s"$prefix.$dimension" - } - unPrefixedDimensions ++ prefixedDimensions - } - - private def multipleSortingQueryGen(validDimensions: Set[String]): Gen[String] = { - val validDimensionsSeq = validDimensions.toSeq - val indexGen = Gen.oneOf(validDimensionsSeq.indices) - val multipleDimensionsGen = Gen.nonEmptyContainerOf[Set, Int](indexGen).filter(_.size >= 2).map { indices => - indices.map(validDimensionsSeq.apply) - } - - for { - dimensions <- multipleDimensionsGen - isAscending <- Gen.containerOfN[Seq, Boolean](dimensions.size, arbitrary[Boolean]) - } yield { - isAscending - .zip(dimensions) - .map { - case (true, dimension) => dimension - case (false, dimension) => "-" + dimension - } - .mkString(",") - } - } - - private def singleSortingQueryGen(validDimensions: Set[String]): Gen[String] = - for { - isAscending <- arbitrary[Boolean] - dimensions <- Gen.oneOf(validDimensions.toSeq) - } yield - isAscending match { - case true => dimensions - case false => "-" + dimensions - } - -} diff --git a/src/test/scala/xyz/driver/pdsuicommon/parsers/TestUtils.scala b/src/test/scala/xyz/driver/pdsuicommon/parsers/TestUtils.scala deleted file mode 100644 index 8ab2131..0000000 --- a/src/test/scala/xyz/driver/pdsuicommon/parsers/TestUtils.scala +++ /dev/null @@ -1,53 +0,0 @@ -package xyz.driver.pdsuicommon.parsers - -import org.scalacheck.Prop -import org.scalacheck.Prop.BooleanOperators -import org.scalatest.matchers.{MatchResult, Matcher} -import xyz.driver.pdsuicommon.utils.Utils - -import scala.reflect.ClassTag -import scala.util.{Failure, Success, Try} - -object TestUtils { - - object success extends Matcher[Try[Any]] { - override def apply(left: Try[Any]) = { - MatchResult(left.isSuccess, s"$left did not fail", s"did fail with $left") - } - } - - class FailWith[ThrowableT <: Throwable](implicit ct: ClassTag[ThrowableT]) extends Matcher[Try[Any]] { - override def apply(left: Try[Any]): MatchResult = { - MatchResult( - left.isFailure && left.failed.get.getClass == ct.runtimeClass, - left match { - case Success(_) => s"$left did not fail" - case Failure(e) => - s"$left did fail with ${Utils.getClassSimpleName(e.getClass)}, " + - s"not ${Utils.getClassSimpleName(ct.runtimeClass)}" - }, - left match { - case Success(_) => s"$left failed with ${Utils.getClassSimpleName(ct.runtimeClass)}" - case Failure(e) => s"$left failed with ${Utils.getClassSimpleName(e.getClass)}" - } - ) - } - } - - def failWith[ThrowableT <: Throwable](implicit ct: ClassTag[ThrowableT]) = new FailWith[ThrowableT] - - final implicit class TryPropOps(val self: Try[Any]) extends AnyVal { - - def successProp: Prop = self match { - case Success(_) => true :| "ok" - case Failure(e) => false :| e.getMessage - } - - def failureProp: Prop = self match { - case Success(x) => false :| s"invalid: $x" - case Failure(_) => true - } - - } - -} diff --git a/src/test/scala/xyz/driver/pdsuicommon/utils/StringOpsSuite.scala b/src/test/scala/xyz/driver/pdsuicommon/utils/StringOpsSuite.scala deleted file mode 100644 index bd0bd2b..0000000 --- a/src/test/scala/xyz/driver/pdsuicommon/utils/StringOpsSuite.scala +++ /dev/null @@ -1,33 +0,0 @@ -package xyz.driver.pdsuicommon.utils - -import xyz.driver.pdsuicommon.utils.Implicits.toStringOps -import org.scalatest.FreeSpecLike - -class StringOpsSuite extends FreeSpecLike { - - "safeTrim" - { - "empty string" in { - assert("".safeTrim == "") - } - - "string with whitespace symbols" in { - assert("\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000".safeTrim == "") - } - - "string with control symbols" in { - assert("\u001f\u007f\t\n".safeTrim == "") - } - - "whitespaces and control symbols from the left side" in { - assert("\u001f\u2002\u007f\nfoo".safeTrim == "foo") - } - - "whitespaces and control symbols from the right side" in { - assert("foo\u001f\u2002\u007f\n".safeTrim == "foo") - } - - "already trimmed string" in { - assert("foo".safeTrim == "foo") - } - } -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/DocumentSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/DocumentSuite.scala deleted file mode 100644 index ccd5a3a..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/DocumentSuite.scala +++ /dev/null @@ -1,94 +0,0 @@ -package xyz.driver.pdsuidomain - -import java.time.{LocalDate, LocalDateTime} -import java.time.temporal.ChronoUnit - -import org.scalatest.FreeSpecLike -import org.scalatest.concurrent.ScalaFutures -import org.scalatest.time.{Millis, Span} -import xyz.driver.pdsuicommon.domain.{LongId, TextJson} -import xyz.driver.pdsuidomain.entities.Document - -class DocumentSuite extends FreeSpecLike with ScalaFutures { - - implicit val defaultPatience: PatienceConfig = - PatienceConfig(timeout = Span(1000, Millis), interval = Span(20, Millis)) - - "validation" - { - "can't submit invalid data" - { - val base = sampleDocument - - val now = LocalDate.now() - val past1 = now.minus(2, ChronoUnit.DAYS) - val past2 = past1.plus(1, ChronoUnit.DAYS) - val future1 = now.plus(1, ChronoUnit.DAYS) - val future2 = future1.plus(1, ChronoUnit.DAYS) - - Seq( - "startDate should be non-empty" -> base.copy(startDate = None), - "startDate should be greater, than endDate" -> base.copy(startDate = Some(past2), endDate = Some(past1)), - "startDate and endDate should be in the past" -> base.copy(startDate = Some(future1), endDate = Some(future2)) - ).foreach { - case (title, orig) => - s"$title" in { - val r = Document.validator(orig) - assert(r.isLeft, s"should fail, but: ${r.right}") - } - } - } - } - - "getRequiredType" - { - "getOPNType" in { - val documentForOPNType = sampleDocument.copy( - typeId = Some(LongId(1L)), - providerTypeId = Some(LongId(1L)), - startDate = Some(LocalDate.now().minus(2, ChronoUnit.DAYS)) - ) - val r = documentForOPNType.getRequiredType("Outpatient Physician Note", "Medical Oncology") - assert(r.contains(Document.RequiredType.OPN), s"document should have the requiredType=OPN, but:$r") - } - - "getPNType" in { - val documentForPNType = sampleDocument.copy( - typeId = Some(LongId(6)) - ) - val r = documentForPNType.getRequiredType("Pathology Report", "") - assert(r.contains(Document.RequiredType.PN), s"document should have the requiredType=PN, but:$r") - } - "get None" in { - val document = sampleDocument.copy( - typeId = Some(LongId(1L)), - providerTypeId = Some(LongId(1L)), - startDate = Some(LocalDate.now().minus(7, ChronoUnit.MONTHS)) - ) - val r = document.getRequiredType("Outpatient Physician Note", "Medical Oncology") - assert(r.isEmpty, s"document should have the requiredType=None, but:$r") - } - } - - private def sampleDocument = { - val lastUpdate = LocalDateTime.now() - - Document( - id = LongId(2002), - status = Document.Status.New, - previousStatus = None, - assignee = None, - previousAssignee = None, - lastActiveUserId = None, - recordId = LongId(2003), - physician = None, - typeId = Some(LongId(123)), - providerName = Some("etst"), - providerTypeId = Some(LongId(123)), - requiredType = None, - institutionName = Some("institution name"), - startDate = Some(lastUpdate.toLocalDate.minusDays(2)), - endDate = None, - lastUpdate = lastUpdate, - meta = Some(TextJson(Document.Meta(1.1, 2.2))), - labelVersion = 1 - ) - } -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ArmFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/ArmFormatSuite.scala deleted file mode 100644 index 3cab4a1..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ArmFormatSuite.scala +++ /dev/null @@ -1,37 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities.Arm - -class ArmFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.arm._ - - "Json format for Arm" should "read and write correct JSON" in { - val arm = Arm( - id = LongId(10), - trialId = StringId("NCT000001"), - name = "arm name", - originalName = "orig arm name" - ) - val writtenJson = armFormat.write(arm) - - writtenJson should be( - """{"id":10,"trialId":"NCT000001","name":"arm name","originalName":"orig arm name"}""".parseJson) - - val createArmJson = """{"trialId":"NCT000001","name":"arm name"}""".parseJson - val parsedArm = armFormat.read(createArmJson) - val expectedCreatedArm = arm.copy( - id = LongId(0), - originalName = "arm name" - ) - parsedArm should be(expectedCreatedArm) - - val updateArmJson = """{"name":"new arm name"}""".parseJson - val expectedUpdatedArm = arm.copy(name = "new arm name") - val parsedUpdateArm = applyUpdateToArm(updateArmJson, arm) - parsedUpdateArm should be(expectedUpdatedArm) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/BridgeUploadQueueFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/BridgeUploadQueueFormatSuite.scala deleted file mode 100644 index 9aaecae..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/BridgeUploadQueueFormatSuite.scala +++ /dev/null @@ -1,32 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue - -class BridgeUploadQueueFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.bridgeuploadqueue._ - - "Json format for BridgeUploadQueue.Item" should "read and write correct JSON" in { - val item = BridgeUploadQueue.Item( - kind = "kind", - tag = "tag", - created = LocalDateTime.parse("2017-08-10T18:00:00"), - attempts = 0, - nextAttempt = LocalDateTime.parse("2017-08-10T18:10:00"), - completed = false, - dependencyKind = Some("dependency king"), - dependencyTag = None - ) - val writtenJson = queueUploadItemFormat.write(item) - - writtenJson should be( - """{"kind":"kind","tag":"tag","created":"2017-08-10T18:00Z","attempts":0,"nextAttempt":"2017-08-10T18:10Z","completed":false}""".parseJson) - - val parsedItem = queueUploadItemFormat.read(writtenJson) - parsedItem should be(item.copy(dependencyKind = None, completed = true)) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/CriterionFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/CriterionFormatSuite.scala deleted file mode 100644 index a227afa..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/CriterionFormatSuite.scala +++ /dev/null @@ -1,75 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities.{EligibilityArm, Criterion, CriterionLabel} -import xyz.driver.pdsuidomain.services.CriterionService.RichCriterion - -class CriterionFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.criterion._ - - "Json format for Criterion" should "read and write correct JSON" in { - val criterion = Criterion( - id = LongId(10), - trialId = StringId("NCT000001"), - text = Some("text"), - isCompound = false, - meta = "{}", - inclusion = None - ) - val labels = List( - CriterionLabel( - id = LongId(1L), - labelId = Some(LongId(101)), - criterionId = criterion.id, - categoryId = Some(LongId(3)), - value = Some(true), - isDefining = true - ), - CriterionLabel( - id = LongId(2L), - labelId = Some(LongId(102)), - criterionId = criterion.id, - categoryId = Some(LongId(3)), - value = Some(false), - isDefining = true - ) - ) - val arms = List(LongId[EligibilityArm](20), LongId[EligibilityArm](21), LongId[EligibilityArm](21)) - val richCriterion = RichCriterion( - criterion = criterion, - armIds = arms, - labels = labels - ) - val writtenJson = richCriterionFormat.write(richCriterion) - - writtenJson should be( - """{"text":"text","isCompound":false,"trialId":"NCT000001","inclusion":null,"arms":[20,21,21],"id":10,"meta":"{}", - "labels":[{"labelId":101,"categoryId":3,"value":"Yes","isDefining":true}, - {"labelId":102,"categoryId":3,"value":"No","isDefining":true}]}""".parseJson) - - val createCriterionJson = - """{"text":"text","isCompound":false,"trialId":"NCT000001","inclusion":null, - "arms":[20,21,21],"meta":"{}","labels":[{"labelId":101,"categoryId":3,"value":"Yes","isDefining":true}, - {"labelId":102,"categoryId":3,"value":"No","isDefining":true}]}""".parseJson - val parsedRichCriterion = richCriterionFormat.read(createCriterionJson) - val expectedRichCriterion = richCriterion.copy( - criterion = criterion.copy(id = LongId(0)), - labels = labels.map(_.copy(id = LongId(0), criterionId = LongId(0))) - ) - parsedRichCriterion should be(expectedRichCriterion) - - val updateCriterionJson = """{"meta":null,"text":"new text","isCompound":true,"inclusion":true}""".parseJson - val expectedUpdatedCriterion = richCriterion.copy( - criterion = criterion.copy( - text = Some("new text"), - isCompound = true, - meta = "{}", - inclusion = Some(true) - )) - val parsedUpdateCriterion = applyUpdateToCriterion(updateCriterionJson, richCriterion) - parsedUpdateCriterion should be(expectedUpdatedCriterion) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentFormatSuite.scala deleted file mode 100644 index 5e33805..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentFormatSuite.scala +++ /dev/null @@ -1,73 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.{LocalDate, LocalDateTime} - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuicommon.domain.{LongId, TextJson} -import xyz.driver.pdsuidomain.entities.Document - -class DocumentFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.document._ - - "Json format for Document" should "read and write correct JSON" in { - val orig = Document( - id = LongId(1), - status = Document.Status.New, - assignee = None, - previousStatus = None, - previousAssignee = None, - lastActiveUserId = None, - lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00"), - recordId = LongId(101), - physician = Some("physician"), - typeId = Some(LongId(10)), - providerName = Some("provider 21"), - providerTypeId = Some(LongId(21)), - institutionName = Some("institution name"), - requiredType = Some(Document.RequiredType.OPN), - meta = None, - startDate = None, - endDate = None, - labelVersion = 0 - ) - val writtenJson = documentFormat.write(orig) - - writtenJson should be( - """{"id":1,"recordId":101,"physician":"physician","typeId":10,"provider":"provider 21","providerTypeId":21, - "requiredType":"OPN","institutionName":"institution name","startDate":null,"endDate":null,"status":"New","assignee":null,"previousStatus":null, - "previousAssignee":null,"lastActiveUser":null,"lastUpdate":"2017-08-10T18:00Z","meta":null,"labelVersion":0}""".parseJson) - - val createDocumentJson = - """{"recordId":101,"physician":"physician","typeId":10,"provider":"provider 21","providerTypeId":21}""".parseJson - val expectedCreatedDocument = orig.copy( - id = LongId(0), - lastUpdate = LocalDateTime.MIN, - requiredType = None, - institutionName = None - ) - val parsedCreatedDocument = documentFormat.read(createDocumentJson) - parsedCreatedDocument should be(expectedCreatedDocument) - - val updateDocumentJson = - """{"startDate":"2017-08-10","endDate":"2018-08-10","meta":{"startPage":1.0,"endPage":2.0}}""".parseJson - val expectedUpdatedDocument = orig.copy( - startDate = Some(LocalDate.parse("2017-08-10")), - endDate = Some(LocalDate.parse("2018-08-10")), - meta = Some(TextJson(Document.Meta(startPage = 1.0, endPage = 2.0))) - ) - val parsedUpdatedDocument = applyUpdateToDocument(updateDocumentJson, orig) - parsedUpdatedDocument should be(expectedUpdatedDocument) - } - - "Json format for Document.Meta" should "read and write correct JSON" in { - val meta = Document.Meta(startPage = 1.0, endPage = 2.0) - val writtenJson = documentMetaFormat.write(meta) - writtenJson should be("""{"startPage":1.0,"endPage":2.0}""".parseJson) - - val metaJson = """{"startPage":1.0,"endPage":2.0}""".parseJson - val parsedMeta = documentMetaFormat.read(metaJson) - parsedMeta should be(meta) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentHistoryFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentHistoryFormatSuite.scala deleted file mode 100644 index d85a53b..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentHistoryFormatSuite.scala +++ /dev/null @@ -1,49 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import org.scalatest.{FreeSpecLike, Matchers} -import spray.json._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities.DocumentHistory - -class DocumentHistoryFormatSuite extends FreeSpecLike with Matchers { - import xyz.driver.pdsuidomain.formats.json.documenthistory._ - - "Can read and write DocumentHistory states" - { - val states = DocumentHistory.State.All - states.foreach { state =>s"$state" in test(state)} - } - - "Can read and write DocumentHistory actions" - { - val actions = DocumentHistory.Action.All - actions.foreach { action =>s"$action" in test(action)} - } - - private def test(state: DocumentHistory.State) = { - documentStateFormat.read(documentStateFormat.write(state)) shouldBe state - } - - private def test(action: DocumentHistory.Action) = { - documentActionFormat.read(documentActionFormat.write(action)) shouldBe action - } - - "Json format for DocumentHistory should read and write correct JSON" - { - val documentHistory = DocumentHistory( - id = LongId(10), - documentId = LongId(1), - executor = xyz.driver.core.Id("userId-001"), - state = DocumentHistory.State.Extract, - action = DocumentHistory.Action.Start, - created = LocalDateTime.parse("2017-08-10T18:00:00") - ) - val writtenJson = documentHistoryFormat.write(documentHistory) - - writtenJson should be("""{"id":10,"executor":"userId-001","documentId":1,"state":"Extract", - "action":"Start","created":"2017-08-10T18:00Z"}""".parseJson) - - val parsedDocumentHistory = documentHistoryFormat.read(writtenJson) - parsedDocumentHistory should be(documentHistory) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentIssueFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentIssueFormatSuite.scala deleted file mode 100644 index 2ddd5e7..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/DocumentIssueFormatSuite.scala +++ /dev/null @@ -1,48 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import org.scalatest.{FlatSpec, Matchers} -import spray.json._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities.DocumentIssue - -class DocumentIssueFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.documentissue._ - - "Json format for DocumentIssue" should "read and write correct JSON" in { - val documentIssue = DocumentIssue( - id = LongId(10), - documentId = LongId(1), - userId = xyz.driver.core.Id("userId-001"), - lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00"), - isDraft = false, - text = "message text", - archiveRequired = false, - startPage = Some(1.0), - endPage = Some(2.0) - ) - val writtenJson = documentIssueFormat.write(documentIssue) - - writtenJson should be( - """{"id":10,"userId":"userId-001","documentId":1,"lastUpdate":"2017-08-10T18:00Z","isDraft":false, - "text":"message text","archiveRequired":false,"startPage":1.0,"endPage":2.0}""".parseJson) - - val createDocumentIssueJson = """{"text":"message text","startPage":1.0,"endPage":2.0}""".parseJson - val expectedCreatedDocumentIssue = - documentIssue.copy(id = LongId(0), lastUpdate = LocalDateTime.MIN, isDraft = true) - val parsedCreateDocumentIssue = jsValueToDocumentIssue(createDocumentIssueJson, LongId(1), xyz.driver.core.Id("userId-001")) - parsedCreateDocumentIssue should be(expectedCreatedDocumentIssue) - - val updateDocumentIssueJson = - """{"text":"new issue text","evidence":"issue evidence","archiveRequired":true,"startPage":1.0,"endPage":4.0}""".parseJson - val expectedUpdatedDocumentIssue = documentIssue.copy( - text = "new issue text", - archiveRequired = true, - endPage = Some(4.0) - ) - val parsedUpdateDocumentIssue = applyUpdateToDocumentIssue(updateDocumentIssueJson, documentIssue) - parsedUpdateDocumentIssue should be(expectedUpdatedDocumentIssue) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/EligibilityArmWithDiseasesFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/EligibilityArmWithDiseasesFormatSuite.scala deleted file mode 100644 index 4203680..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/EligibilityArmWithDiseasesFormatSuite.scala +++ /dev/null @@ -1,56 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.entities.patient.CancerType -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities.{EligibilityArm, EligibilityArmDisease, EligibilityArmWithDiseases} - -class EligibilityArmWithDiseasesFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.eligibilityarm._ - - "Json format for EligibilityArmWithDiseases" should "read and write correct JSON" in { - val name = "arm name" - - val arm = EligibilityArm( - id = LongId(0), - trialId = StringId("NCT000001"), - name = name, - originalName = name - ) - - val disease = EligibilityArmDisease( - arm.id, - disease = CancerType.Lung - ) - - val eligibilityArmWithDiseases = - EligibilityArmWithDiseases( - arm, - Seq(disease) - ) - - val writtenJson = eligibilityArmWithDiseasesWriter.write(eligibilityArmWithDiseases) - - writtenJson should be( - """{"id":0,"trialId":"NCT000001","name":"arm name","originalName":"arm name","diseases":["Lung"]}""".parseJson) - - val createArmWithDiseasesJson = """{"trialId":"NCT000001","name":"arm name","diseases":["Lung"]}""".parseJson - val parsedArmWithDiseases = eligibilityArmWithDiseasesReader.read(createArmWithDiseasesJson) - parsedArmWithDiseases should be(eligibilityArmWithDiseases) - - val updateArmWithDiseasesJson = """{"name":"new arm name","diseases":["Lung","Breast"]}""".parseJson - val expectedUpdatedArmWithDiseases = eligibilityArmWithDiseases.copy( - eligibilityArm = eligibilityArmWithDiseases.eligibilityArm.copy(name = "new arm name"), - eligibilityArmDiseases = Seq(disease, disease.copy(disease = CancerType.Breast)) - ) - - val parsedUpdateArmWithDiseases = - applyUpdateToEligibilityArmWithDiseases( - updateArmWithDiseasesJson, - eligibilityArmWithDiseases - ) - - parsedUpdateArmWithDiseases should be(expectedUpdatedArmWithDiseases) - } -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExportFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExportFormatSuite.scala deleted file mode 100644 index 9c53d3b..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExportFormatSuite.scala +++ /dev/null @@ -1,129 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.{LocalDate, LocalDateTime} - -import org.scalatest.{FlatSpec, Matchers} -import spray.json._ -import xyz.driver.core.Id -import xyz.driver.entities.clinic.ClinicalRecord -import xyz.driver.entities.labels.LabelValue -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} -import xyz.driver.pdsuidomain.entities.{DocumentType, ProviderType} - -class ExportFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.export._ - - "Json format for ExportPatientWithLabels" should "read and write correct JSON" in { - import xyz.driver.pdsuidomain.entities.export.patient._ - val document = ExportPatientLabelEvidenceDocument( - documentId = LongId(101), - requestId = Id[ClinicalRecord]("7b54a75d-4197-4b27-9045-b9b6cb131be9"), - documentType = DocumentType.OutpatientPhysicianNote, - providerType = ProviderType.Surgery, - date = LocalDate.parse("2017-08-10") - ) - - val labels = List( - ExportPatientLabel( - id = LongId(1), - evidences = List( - ExportPatientLabelEvidence( - id = LongId(11), - value = LabelValue.Yes, - evidenceText = "evidence text 11", - document = document - ), - ExportPatientLabelEvidence( - id = LongId(12), - value = LabelValue.No, - evidenceText = "evidence text 12", - document = document - ) - ) - ), - ExportPatientLabel( - id = LongId(2), - evidences = List( - ExportPatientLabelEvidence( - id = LongId(12), - value = LabelValue.Yes, - evidenceText = "evidence text 12", - document = document - ), - ExportPatientLabelEvidence( - id = LongId(13), - value = LabelValue.Yes, - evidenceText = "evidence text 13", - document = document - ) - ) - ) - ) - val patientWithLabels = ExportPatientWithLabels( - patientId = UuidId("748b5884-3528-4cb9-904b-7a8151d6e343"), - labelVersion = 1L, - labels = labels - ) - - val writtenJson = patientWithLabelsFormat.write(patientWithLabels) - writtenJson should be( - """{"patientId":"748b5884-3528-4cb9-904b-7a8151d6e343","labelVersion":1,"labels":[{"labelId":1,"evidence":[{"evidenceId":11, - "labelValue":"Yes","evidenceText":"evidence text 11","document":{"documentId":101,"requestId":"7b54a75d-4197-4b27-9045-b9b6cb131be9", - "documentType":{"id":1,"name":"Outpatient Physician Note"},"providerType":{"id":2,"name":"Surgery"},"date":"2017-08-10"}}, - {"evidenceId":12,"labelValue":"No","evidenceText":"evidence text 12","document":{"documentId":101,"requestId":"7b54a75d-4197-4b27-9045-b9b6cb131be9", - "documentType":{"id":1,"name":"Outpatient Physician Note"},"providerType":{"id":2,"name":"Surgery"},"date":"2017-08-10"}}]}, - {"labelId":2,"evidence":[{"evidenceId":12,"labelValue":"Yes","evidenceText":"evidence text 12","document": - {"documentId":101,"requestId":"7b54a75d-4197-4b27-9045-b9b6cb131be9","documentType":{"id":1,"name":"Outpatient Physician Note"}, - "providerType":{"id":2,"name":"Surgery"},"date":"2017-08-10"}},{"evidenceId":13,"labelValue":"Yes","evidenceText":"evidence text 13", - "document":{"documentId":101,"requestId":"7b54a75d-4197-4b27-9045-b9b6cb131be9","documentType":{"id":1,"name":"Outpatient Physician Note"}, - "providerType":{"id":2,"name":"Surgery"},"date":"2017-08-10"}}]}]}""".parseJson) - } - - "Json format for ApiExportTrialWithLabels" should "read and write correct JSON" in { - import xyz.driver.pdsuidomain.entities.export.trial._ - val arms = List( - ExportTrialArm(armId = LongId(1), armName = "arm 1", diseaseList = Seq("Breast")), - ExportTrialArm(armId = LongId(2), armName = "arm 2", diseaseList = Seq("Breast")) - ) - val criteriaList = List( - ExportTrialLabelCriterion( - criterionId = LongId(10), - value = Some(true), - labelId = LongId(21), - armIds = Set(LongId(1), LongId(2)), - criteria = "criteria 10 text", - isCompound = false, - isDefining = false, - inclusion = Some(false) - ), - ExportTrialLabelCriterion( - criterionId = LongId(11), - value = None, - labelId = LongId(21), - armIds = Set(LongId(2)), - criteria = "criteria 11 text", - isCompound = true, - isDefining = false, - inclusion = None - ) - ) - val trialWithLabels = ExportTrialWithLabels( - nctId = StringId("NCT000001"), - trialId = UuidId("40892a07-c638-49d2-9795-1edfefbbcc7c"), - lastReviewed = LocalDateTime.parse("2017-08-10T18:00:00"), - labelVersion = 1L, - arms = arms, - criteria = criteriaList - ) - - val writtenJson = trialWithLabelsFormat.write(trialWithLabels) - writtenJson should be( - """{"nctId":"NCT000001","trialId":"40892a07-c638-49d2-9795-1edfefbbcc7c","lastReviewed":"2017-08-10T18:00Z", - "labelVersion":1,"arms":[{"armId":1,"armName":"arm 1","diseaseList":["Breast"]},{"armId":2,"armName":"arm 2","diseaseList":["Breast"]}],"criteria":[ - {"value":"Yes","labelId":21,"criterionId":10,"criterionText":"criteria 10 text","armIds":[1,2],"isCompound":false, - "isDefining":false,"inclusion":false}, - {"value":"Unknown","labelId":21,"criterionId":11,"criterionText":"criteria 11 text","armIds":[2],"isCompound":true, - "isDefining":false,"inclusion":null}]}""".parseJson) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExtractedDataFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExtractedDataFormatSuite.scala deleted file mode 100644 index d1d8d44..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ExtractedDataFormatSuite.scala +++ /dev/null @@ -1,109 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.entities.labels.LabelValue -import xyz.driver.pdsuicommon.domain.{LongId, TextJson} -import xyz.driver.pdsuidomain.entities.ExtractedData.Meta -import xyz.driver.pdsuidomain.entities.{ExtractedData, ExtractedDataLabel} -import xyz.driver.pdsuidomain.services.ExtractedDataService.RichExtractedData - -class ExtractedDataFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.extracteddata._ - - "Json format for ExtractedData" should "read and write correct JSON" in { - val extractedData = ExtractedData( - id = LongId(1), - documentId = LongId(101), - keywordId = Some(LongId(201)), - evidenceText = Some("evidence text"), - meta = Option(TextJson(Meta( - evidence = None, - keyword = - Some(Meta.Keyword( - page = 1, - pageRatio = Some(1.6161616161616161d), - index = 0, - sortIndex = "1080000" - )) - ) - ))) - - val extractedDataLabels = List( - ExtractedDataLabel( - id = LongId(1), - dataId = extractedData.id, - labelId = None, - categoryId = None, - value = Some(LabelValue.Yes) - ), - ExtractedDataLabel( - id = LongId(2), - dataId = extractedData.id, - labelId = Some(LongId(12)), - categoryId = Some(LongId(1)), - value = Some(LabelValue.No) - ) - ) - val origRichExtractedData = RichExtractedData( - extractedData = extractedData, - labels = extractedDataLabels - ) - val writtenJson = extractedDataFormat.write(origRichExtractedData) - - writtenJson should be( - """{"id":1,"documentId":101,"keywordId":201,"evidence":"evidence text","meta":null, - "labels":[{"id":null,"categoryId":null,"value":"Yes"},{"id":12,"categoryId":1,"value":"No"}], - "meta":{"keyword":{"index":0,"page":1,"pageRatio":1.6161616161616161,"sortIndex":"1080000"}}}""".parseJson) - - val createExtractedDataJson = - """{"documentId":101,"keywordId":201,"evidence":"evidence text", - "labels":[{"value":"Yes"},{"id":12,"categoryId":1,"value":"No"}], - "meta":{"keyword":{"index":0,"page":1,"pageRatio":1.6161616161616161,"sortIndex":"1080000"}}}""".parseJson - val expectedCreatedExtractedData = origRichExtractedData.copy( - extractedData = extractedData.copy(id = LongId(0)), - labels = extractedDataLabels.map(_.copy(id = LongId(0), dataId = LongId(0))) - ) - val parsedCreatedExtractedData = extractedDataFormat.read(createExtractedDataJson) - parsedCreatedExtractedData should be(expectedCreatedExtractedData) - - val updateExtractedDataJson = - """{"evidence":"new evidence text","meta":{"keyword":{"page":1,"index":2,"sortIndex":"ASC"}, - "evidence":{"pageRatio":1.0,"start":{"page":1,"index":3,"offset":2},"end":{"page":2,"index":3,"offset":10}}}, - "labels":[{"id":20,"categoryId":1,"value":"Yes"},{"id":12,"categoryId":1,"value":"No"}]}""".parseJson - val updatedExtractedDataLabels = List( - ExtractedDataLabel( - id = LongId(0), - dataId = extractedData.id, - labelId = Some(LongId(20)), - categoryId = Some(LongId(1)), - value = Some(LabelValue.Yes) - ), - ExtractedDataLabel( - id = LongId(0), - dataId = extractedData.id, - labelId = Some(LongId(12)), - categoryId = Some(LongId(1)), - value = Some(LabelValue.No) - ) - ) - val expectedUpdatedExtractedData = origRichExtractedData.copy( - extractedData = extractedData.copy( - evidenceText = Some("new evidence text"), - meta = Some( - TextJson(Meta( - keyword = Some(Meta.Keyword(page = 1, pageRatio = None, index = 2, sortIndex = "ASC")), - evidence = Some(Meta.Evidence( - pageRatio = 1.0, - start = Meta.TextLayerPosition(page = 1, index = 3, offset = 2), - end = Meta.TextLayerPosition(page = 2, index = 3, offset = 10) - )) - ))) - ), - labels = updatedExtractedDataLabels - ) - val parsedUpdatedExtractedData = applyUpdateToExtractedData(updateExtractedDataJson, origRichExtractedData) - parsedUpdatedExtractedData should be(expectedUpdatedExtractedData) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/HypothesisFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/HypothesisFormatSuite.scala deleted file mode 100644 index 6d51873..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/HypothesisFormatSuite.scala +++ /dev/null @@ -1,27 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuidomain.entities.Hypothesis - -class HypothesisFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.hypothesis._ - - "Json format for Hypothesis" should "read and write correct JSON" in { - val hypothesis = Hypothesis( - id = UuidId("3b80b2e2-5372-4cf5-a342-6e4ebe10fafd"), - name = "hypothesis name", - treatmentType = "treatment type", - description = "descr" - ) - val writtenJson = hypothesisFormat.write(hypothesis) - - writtenJson should be("""{"id":"3b80b2e2-5372-4cf5-a342-6e4ebe10fafd","name":"hypothesis name", - "treatmentType":"treatment type","description":"descr"}""".parseJson) - - val parsedHypothesis = hypothesisFormat.read(writtenJson) - parsedHypothesis should be(hypothesis) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/InterventionFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/InterventionFormatSuite.scala deleted file mode 100644 index 015c7b5..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/InterventionFormatSuite.scala +++ /dev/null @@ -1,73 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities.{Intervention, InterventionArm, InterventionType, InterventionWithArms} - -class InterventionFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.intervention._ - - "Json format for Intervention" should "read and write correct JSON" in { - val intervention = Intervention( - id = LongId(1), - trialId = StringId("NCT000001"), - name = "intervention name", - originalName = "orig name", - typeId = Some(LongId(10)), - originalType = Some("orig type"), - dosage = "", - originalDosage = "", - isActive = true, - deliveryMethod = Some("Inhalation") - ) - val arms = List( - InterventionArm(interventionId = intervention.id, armId = LongId(20)), - InterventionArm(interventionId = intervention.id, armId = LongId(21)), - InterventionArm(interventionId = intervention.id, armId = LongId(22)) - ) - val orig = InterventionWithArms( - intervention = intervention, - arms = arms - ) - val writtenJson = interventionFormat.write(orig) - - writtenJson should be( - """{"id":1,"name":"intervention name","typeId":10,"dosage":"","isActive":true,"arms":[20,21,22], - "trialId":"NCT000001","deliveryMethod":"Inhalation","originalName":"orig name","originalDosage":"","originalType":"orig type"}""".parseJson) - - val createInterventionJson = - """{"id":1,"name":"intervention name","typeId":10,"dosage":"","isActive":true,"arms":[20,21,22], - "trialId":"NCT000001","deliveryMethod":"Inhalation"}""".parseJson - val parsedCreateIntervention = interventionFormat.read(createInterventionJson) - val expectedCreateIntervention = parsedCreateIntervention.copy( - intervention = intervention.copy(id = LongId(0), originalType = None, originalName = "intervention name"), - arms = arms.map(_.copy(interventionId = LongId(0))) - ) - parsedCreateIntervention should be(expectedCreateIntervention) - - val updateInterventionJson = """{"dosage":"descr","deliveryMethod":null,"arms":[21,22]}""".parseJson - val expectedUpdatedIntervention = orig.copy( - intervention = intervention.copy(dosage = "descr", deliveryMethod = None), - arms = List( - InterventionArm(interventionId = intervention.id, armId = LongId(21)), - InterventionArm(interventionId = intervention.id, armId = LongId(22)) - ) - ) - val parsedUpdateIntervention = applyUpdateToInterventionWithArms(updateInterventionJson, orig) - parsedUpdateIntervention should be(expectedUpdatedIntervention) - } - - "Json format for InterventionType" should "read and write correct JSON" in { - val interventionType = InterventionType.SurgeryProcedure - val writtenJson = interventionTypeFormat.write(interventionType) - - writtenJson should be( - """{"id":9,"name":"Surgery/Procedure","deliveryMethods":["Radio-Frequency Ablation (RFA)", - "Cryoablation","Therapeutic Conventional Surgery","Robotic Assisted Laparoscopic Surgery"]}""".parseJson) - - val parsedInterventionType = interventionTypeFormat.read(writtenJson) - parsedInterventionType should be(interventionType) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ListResponseFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/ListResponseFormatSuite.scala deleted file mode 100644 index e43e922..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/ListResponseFormatSuite.scala +++ /dev/null @@ -1,102 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.core.Id -import xyz.driver.entities.clinic.ClinicalRecord -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuidomain.ListResponse -import xyz.driver.pdsuidomain.entities.MedicalRecord.Status -import xyz.driver.pdsuidomain.entities._ -import xyz.driver.pdsuidomain.formats.json.record.recordFormat -import xyz.driver.pdsuidomain.formats.json.listresponse._ - - -class ListResponseFormatSuite extends FlatSpec with Matchers { - - private val lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00") - private val lastUpdateToLocal = "2017-08-10T18:00Z" - - def metaJsonObjectAsString(meta: ListResponse.Meta): String = { - import meta._ - val lastUpdate = meta.lastUpdate - .map(_ => s""","lastUpdate":"$lastUpdateToLocal"""") - .getOrElse("") - - s"""{"itemsCount":$itemsCount,"pageNumber":$pageNumber,"pageSize":$pageSize$lastUpdate}""" - } - - "Json format for ListResponse.Meta" should "read and write correct JSON" in { - val meta1 = - ListResponse.Meta( - itemsCount = 5, - pageNumber = 6, - pageSize = 7, - lastUpdate = None - ) - - val writtenJson1 = listResponseMetaFormat.write(meta1) - - writtenJson1 should be(metaJsonObjectAsString(meta1).parseJson) - - val parsedItem1: ListResponse.Meta = listResponseMetaFormat.read(writtenJson1) - - meta1 shouldBe parsedItem1 - - val meta2 = - ListResponse.Meta( - itemsCount = 1, - pageNumber = 4, - pageSize = 3, - lastUpdate = Some(lastUpdate) - ) - - val writtenJson2 = listResponseMetaFormat.write(meta2) - - writtenJson2 should be(metaJsonObjectAsString(meta2).parseJson) - - val parsedItem2: ListResponse.Meta = listResponseMetaFormat.read(writtenJson2) - - meta2 shouldBe parsedItem2 - } - - "Json format for ListResponse" should "write correct JSON" in { - - val orig = MedicalRecord( - id = LongId(1), - status = Status.New, - assignee = None, - previousStatus = None, - previousAssignee = None, - lastActiveUserId = None, - lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00"), - physician = Some("physician"), - meta = None, - disease = "Breast", - requestId = Id[ClinicalRecord]("7b54a75d-4197-4b27-9045-b9b6cb131be9"), - caseId = None, - patientId = UuidId("748b5884-3528-4cb9-904b-7a8151d6e343"), - totalPages = 10 - ) - - val recordJsonAsString = recordFormat.write(orig) - - val meta = - ListResponse.Meta( - itemsCount = 5, - pageNumber = 6, - pageSize = 7, - lastUpdate = None - ) - - val listResponse = ListResponse(Seq(orig), meta) - - val writtenJson = listResponseWriter[MedicalRecord].write(listResponse) - val expectedJson = s"""{"items":[$recordJsonAsString],"meta":${listResponseMetaFormat.write(meta)}}""" - - writtenJson should be(expectedJson.parseJson) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordFormatSuite.scala deleted file mode 100644 index 86462b2..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordFormatSuite.scala +++ /dev/null @@ -1,152 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.core.Id -import xyz.driver.entities.clinic.ClinicalRecord -import xyz.driver.pdsuicommon.domain.{LongId, TextJson, UuidId} -import xyz.driver.pdsuidomain.entities.MedicalRecord - -class MedicalRecordFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.record._ - import MedicalRecord._ - - "Json format for MedicalRecord.Meta" should "read and write correct JSON" in { - val duplicate1 = Meta.Duplicate( - startPage = 1.0d, - endPage = 2.0d, - startOriginalPage = 1.0d, - endOriginalPage = Some(2.0d) - ) - - val duplicate2 = Meta.Duplicate( - startPage = 1.0d, - endPage = 2.0d, - startOriginalPage = 1.0d, - endOriginalPage = None - ) - - val reorder = Meta.Reorder( - Seq(1, 2) - ) - - val rotation = Meta.Rotation( - Map("item1" -> 1, "item2" -> 2) - ) - - val writtenDuplicateJson1 = - duplicateMetaFormat.write(duplicate1) - - val writtenDuplicateJson2 = - duplicateMetaFormat.write(duplicate2) - - val writtenReorderJson = - reorderMetaFormat.write(reorder) - - val writtenRotationJson = - rotateMetaFormat.write(rotation) - - writtenDuplicateJson1 should be( - """{"startOriginalPage":1.0,"endPage":2.0,"startPage":1.0,"type":"duplicate","endOriginalPage":2.0}""".parseJson) - - writtenDuplicateJson2 should be( - """{"startOriginalPage":1.0,"endPage":2.0,"startPage":1.0,"type":"duplicate","endOriginalPage":null}""".parseJson) - - writtenReorderJson should be( - """{"type":"reorder","items":[1,2]}""".parseJson) - - writtenRotationJson should be( - """{"type":"rotation","items":{"item1":1,"item2":2}}""".parseJson) - - val parsedDuplicateJson1 = - duplicateMetaFormat.read(writtenDuplicateJson1) - - val parsedDuplicateJson2 = - duplicateMetaFormat.read(writtenDuplicateJson2) - - val parsedReorderJson = - reorderMetaFormat.read(writtenReorderJson) - - val parsedRotationJson = - rotateMetaFormat.read(writtenRotationJson) - - duplicate1 should be(parsedDuplicateJson1) - - duplicate2 should be(parsedDuplicateJson2) - - reorder should be(parsedReorderJson) - - rotation should be(parsedRotationJson) - - duplicate1 should be(recordMetaTypeFormat.read(recordMetaTypeFormat.write(duplicate1))) - duplicate2 should be(recordMetaTypeFormat.read(recordMetaTypeFormat.write(duplicate2))) - reorder should be(recordMetaTypeFormat.read(recordMetaTypeFormat.write(reorder))) - rotation should be(recordMetaTypeFormat.read(recordMetaTypeFormat.write(rotation))) - } - - - "Json format for MedicalRecord" should "read and write correct JSON" in { - val orig = MedicalRecord( - id = LongId(1), - status = Status.New, - assignee = None, - previousStatus = None, - previousAssignee = None, - lastActiveUserId = None, - lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00"), - physician = Some("physician"), - meta = None, - disease = "Breast", - requestId = Id[ClinicalRecord]("7b54a75d-4197-4b27-9045-b9b6cb131be9"), - caseId = None, - patientId = UuidId("748b5884-3528-4cb9-904b-7a8151d6e343"), - totalPages = 10 - ) - val writtenJson = recordFormat.write(orig) - - writtenJson should be( - """{"id":1,"status":"New","assignee":null,"previousStatus":null,"previousAssignee":null,"lastActiveUser":null, - "lastUpdate":"2017-08-10T18:00Z","meta":[],"patientId":"748b5884-3528-4cb9-904b-7a8151d6e343","caseId":null, - "requestId":"7b54a75d-4197-4b27-9045-b9b6cb131be9","disease":"Breast","physician":"physician","totalPages":10}""".parseJson) - - val createRecordJson = - """{"disease":"Breast","patientId":"748b5884-3528-4cb9-904b-7a8151d6e343","requestId":"7b54a75d-4197-4b27-9045-b9b6cb131be9"}""".parseJson - val expectedCreatedRecord = MedicalRecord( - id = LongId(0), - status = MedicalRecord.Status.New, - previousStatus = None, - assignee = None, - previousAssignee = None, - lastActiveUserId = None, - patientId = UuidId("748b5884-3528-4cb9-904b-7a8151d6e343"), - requestId = Id[ClinicalRecord]("7b54a75d-4197-4b27-9045-b9b6cb131be9"), - disease = "Breast", - caseId = None, - physician = None, - meta = None, - lastUpdate = LocalDateTime.now(), - totalPages = 0 - ) - val parsedCreatedRecord = recordFormat.read(createRecordJson).copy(lastUpdate = expectedCreatedRecord.lastUpdate) - parsedCreatedRecord should be(expectedCreatedRecord) - - val updateRecordJson = - """{"meta":[{"type":"duplicate","startPage":1.0,"endPage":2.0,"startOriginalPage":1.0}, - {"type":"reorder","items":[1,2]}, - {"type":"rotation","items":{"item1":1,"item2":2}}]}""".parseJson - val expectedUpdatedRecord = orig.copy( - meta = Some( - TextJson( - List( - Meta.Duplicate(startPage = 1.0, endPage = 2.0, startOriginalPage = 1.0, endOriginalPage = None), - Meta.Reorder(Seq(1, 2)), - Meta.Rotation(Map("item1" -> 1, "item2" -> 2)) - ))) - ) - val parsedUpdatedRecord = applyUpdateToMedicalRecord(updateRecordJson, orig) - parsedUpdatedRecord should be(expectedUpdatedRecord) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordHistoryFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordHistoryFormatSuite.scala deleted file mode 100644 index c34f8c0..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordHistoryFormatSuite.scala +++ /dev/null @@ -1,51 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import org.scalatest.{FreeSpecLike, Matchers} -import spray.json._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities.MedicalRecordHistory - -class MedicalRecordHistoryFormatSuite extends FreeSpecLike with Matchers { - import xyz.driver.pdsuidomain.formats.json.recordhistory._ - - - "Can read and write MedicalRecordHistory states" - { - val states = MedicalRecordHistory.State.All - states.foreach { state =>s"$state" in test(state)} - } - - "Can read and write MedicalRecordHistory actions" - { - val actions = MedicalRecordHistory.Action.All - actions.foreach { action =>s"$action" in test(action)} - } - - private def test(state: MedicalRecordHistory.State) = { - recordStateFormat.read(recordStateFormat.write(state)) shouldBe state - } - - private def test(action: MedicalRecordHistory.Action) = { - recordActionFormat.read(recordActionFormat.write(action)) shouldBe action - } - - - "Json format for MedicalRecordHistory should read and write correct JSON" - { - val recordHistory = MedicalRecordHistory( - id = LongId(10), - recordId = LongId(1), - executor = xyz.driver.core.Id("userId-001"), - state = MedicalRecordHistory.State.Clean, - action = MedicalRecordHistory.Action.Start, - created = LocalDateTime.parse("2017-08-10T18:00:00") - ) - val writtenJson = recordHistoryFormat.write(recordHistory) - - writtenJson should be("""{"id":10,"executor":"userId-001","recordId":1,"state":"Clean", - "action":"Start","created":"2017-08-10T18:00Z"}""".parseJson) - - val parsedRecordHistory = recordHistoryFormat.read(writtenJson) - parsedRecordHistory should be(recordHistory) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordIssueFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordIssueFormatSuite.scala deleted file mode 100644 index b93e2bd..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/MedicalRecordIssueFormatSuite.scala +++ /dev/null @@ -1,47 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import org.scalatest.{FlatSpec, Matchers} -import spray.json._ -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities.MedicalRecordIssue - -class MedicalRecordIssueFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.recordissue._ - - "Json format for MedicalRecordIssue" should "read and write correct JSON" in { - val recordIssue = MedicalRecordIssue( - id = LongId(10), - recordId = LongId(1), - userId = xyz.driver.core.Id("userId-001"), - lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00"), - isDraft = false, - text = "message text", - archiveRequired = false, - startPage = Some(1.0), - endPage = Some(2.0) - ) - val writtenJson = recordIssueFormat.write(recordIssue) - - writtenJson should be( - """{"id":10,"recordId":1,"userId":"userId-001","lastUpdate":"2017-08-10T18:00Z","isDraft":false, - "text":"message text","archiveRequired":false,"startPage":1.0,"endPage":2.0}""".parseJson) - - val createRecordIssueJson = """{"text":"message text","startPage":1.0,"endPage":2.0}""".parseJson - val expectedCreatedRecordIssue = recordIssue.copy(id = LongId(0), lastUpdate = LocalDateTime.MIN, isDraft = true) - val parsedCreateRecordIssue = jsValueToRecordIssue(createRecordIssueJson, LongId(1), xyz.driver.core.Id("userId-001")) - parsedCreateRecordIssue should be(expectedCreatedRecordIssue) - - val updateRecordIssueJson = - """{"text":"new issue text","evidence":"issue evidence","archiveRequired":true,"startPage":1.0,"endPage":4.0}""".parseJson - val expectedUpdatedRecordIssue = recordIssue.copy( - text = "new issue text", - archiveRequired = true, - endPage = Some(4.0) - ) - val parsedUpdateRecordIssue = applyUpdateToRecordIssue(updateRecordIssueJson, recordIssue) - parsedUpdateRecordIssue should be(expectedUpdatedRecordIssue) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientCriterionFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientCriterionFormatSuite.scala deleted file mode 100644 index 370173a..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientCriterionFormatSuite.scala +++ /dev/null @@ -1,60 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.entities.labels.LabelValue -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities.{DraftPatientCriterion, PatientCriterion, PatientCriterionArm, RichPatientCriterion} - -class PatientCriterionFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.patientcriterion._ - - "Json format for PatientCriterion" should "read and write correct JSON" in { - val orig = PatientCriterion( - id = LongId(1), - patientLabelId = LongId(1), - trialId = 0L, - nctId = StringId("NCT00001"), - criterionId = LongId(101), - criterionText = "criterion text", - criterionValue = Some(true), - criterionIsDefining = false, - eligibilityStatus = LabelValue.Yes, - verifiedEligibilityStatus = LabelValue.Unknown, - isVisible = true, - isVerified = true, - lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00"), - inclusion = Some(true) - ) - val arms = List( - PatientCriterionArm(patientCriterionId = LongId(1), armId = LongId(31), armName = "arm 31"), - PatientCriterionArm(patientCriterionId = LongId(1), armId = LongId(32), armName = "arm 32") - ) - val richPatientCriterion = RichPatientCriterion(orig, LongId(21), arms) - val writtenJson = richPatientCriterionFormat.write(richPatientCriterion) - - writtenJson should be( - """{"isVerified":true,"patientLabelId":1,"lastUpdate":"2017-08-10T18:00Z","trialId":0, - "armList":[{"patientCriterionId":1,"armId":31,"armName":"arm 31"},{"patientCriterionId":1, - "armId":32,"armName":"arm 32"}],"eligibilityStatus":"Yes","verifiedEligibilityStatus":"Unknown","id":1,"nctId":"NCT00001", - "criterionId":101,"criterionValue":true,"criterionIsDefining":false,"labelId":21, - "isVisible":true,"criterionText":"criterion text","inclusion":true}""".parseJson) - - val updatePatientCriterionJson = """{"verifiedEligibilityStatus":"No"}""".parseJson - val expectedUpdatedPatientCriterion = orig.copy(verifiedEligibilityStatus = LabelValue.No) - val parsedUpdatePatientCriterion = applyUpdateToPatientCriterion(updatePatientCriterionJson, orig) - parsedUpdatePatientCriterion should be(expectedUpdatedPatientCriterion) - - val updateBulkPatientCriterionJson = - """[{"id":1,"eligibilityStatus":"No"},{"id":2,"isVerified":false}]""".parseJson - val expectedDraftPatientCriterionList = List( - DraftPatientCriterion(id = LongId(1), eligibilityStatus = Some(LabelValue.No), isVerified = None), - DraftPatientCriterion(id = LongId(2), eligibilityStatus = None, isVerified = Some(false)) - ) - val parsedDraftPatientCriterionList = draftPatientCriterionListReader.read(updateBulkPatientCriterionJson) - parsedDraftPatientCriterionList should be(expectedDraftPatientCriterionList) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientEligibleTrialFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientEligibleTrialFormatSuite.scala deleted file mode 100644 index 6f3bc19..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientEligibleTrialFormatSuite.scala +++ /dev/null @@ -1,61 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import org.scalatest.{FlatSpec, Matchers} -import spray.json._ -import xyz.driver.entities.labels.LabelValue -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} -import xyz.driver.pdsuidomain.entities.{PatientCriterionArm, PatientTrialArmGroupView, RichPatientEligibleTrial, Trial} - -class PatientEligibleTrialFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.patienteligibletrial._ - - "Json format for PatientEligibleTrial" should "read and write correct JSON" in { - val trial = Trial( - id = StringId("NCT000001"), - externalId = UuidId("40892a07-c638-49d2-9795-1edfefbbcc7c"), - status = Trial.Status.Done, - assignee = None, - previousStatus = None, - previousAssignee = None, - lastActiveUserId = None, - lastUpdate = LocalDateTime.parse("2017-08-10T18:16:19"), - phase = "", - hypothesisId = Some(UuidId("e76e2fc4-a29c-44fb-a81b-8856d06bb1d4")), - studyDesignId = Some(LongId(321)), - originalStudyDesign = None, - isPartner = false, - overview = None, - overviewTemplate = "", - isUpdated = false, - title = "trial title", - originalTitle = "orig trial title" - ) - val group = PatientTrialArmGroupView( - id = LongId(1), - patientId = UuidId("748b5884-3528-4cb9-904b-7a8151d6e343"), - trialId = StringId("NCT000001"), - hypothesisId = UuidId("e76e2fc4-a29c-44fb-a81b-8856d06bb1d4"), - eligibilityStatus = LabelValue.Yes, - verifiedEligibilityStatus = LabelValue.Yes, - isVerified = false - ) - val arms = List( - PatientCriterionArm(patientCriterionId = LongId(1), armId = LongId(31), armName = "arm 31"), - PatientCriterionArm(patientCriterionId = LongId(1), armId = LongId(32), armName = "arm 32") - ) - val orig = RichPatientEligibleTrial(trial, group, arms) - val writtenJson = patientEligibleTrialWriter.write(orig) - - writtenJson should be( - """{"id":1,"patientId":"748b5884-3528-4cb9-904b-7a8151d6e343","trialId":"NCT000001","trialTitle":"trial title", - "hypothesisId":"e76e2fc4-a29c-44fb-a81b-8856d06bb1d4","verifiedEligibilityStatus":"Yes","isVerified":false,"arms":["arm 31","arm 32"]}""".parseJson) - - val updatePatientEligibleTrialJson = """{"isVerified":true}""".parseJson - val expectedUpdatedPatientTrialArmGroup = group.copy(isVerified = true) - val parsedUpdatePatientTrialArmGroup = applyUpdateToTrialArmGroup(updatePatientEligibleTrialJson, group) - parsedUpdatePatientTrialArmGroup should be(expectedUpdatedPatientTrialArmGroup) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientFormatSuite.scala deleted file mode 100644 index 6cddb45..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientFormatSuite.scala +++ /dev/null @@ -1,41 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.{LocalDate, LocalDateTime} - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.core.Id -import xyz.driver.entities.clinic.TestOrder -import xyz.driver.entities.common.FullName -import xyz.driver.entities.patient.CancerType -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuidomain.entities.Patient - -class PatientFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.patient._ - - "Json format for Patient" should "read and write correct JSON" in { - val orig = Patient( - id = UuidId("748b5884-3528-4cb9-904b-7a8151d6e343"), - status = Patient.Status.New, - name = FullName.fromStrings("John", "", "Doe"), - dob = LocalDate.parse("1980-06-30"), - assignee = None, - previousStatus = None, - previousAssignee = None, - lastActiveUserId = None, - isUpdateRequired = false, - disease = CancerType.Breast, - orderId = Id[TestOrder]("7b54a75d-4197-4b27-9045-b9b6cb131be9"), - lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00") - ) - val writtenJson = patientFormat.write(orig) - - writtenJson should be( - """{"id":"748b5884-3528-4cb9-904b-7a8151d6e343","dob":"1980-06-30", - "name":{"firstName":"John","middleName":"","lastName":"Doe"},"status":"New","assignee":null, - "previousStatus":null,"previousAssignee":null,"lastActiveUser":null,"lastUpdate":"2017-08-10T18:00Z", - "orderId":"7b54a75d-4197-4b27-9045-b9b6cb131be9","disease":"Breast"}""".parseJson) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientHistoryFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientHistoryFormatSuite.scala deleted file mode 100644 index 74f6f70..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientHistoryFormatSuite.scala +++ /dev/null @@ -1,32 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import org.scalatest.{FlatSpec, Matchers} -import spray.json._ -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuidomain.entities.PatientHistory - -class PatientHistoryFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.patienthistory._ - - "Json format for PatientHistory" should "read and write correct JSON" in { - val patientHistory = PatientHistory( - id = LongId(10), - patientId = UuidId("40892a07-c638-49d2-9795-1edfefbbcc7c"), - executor = xyz.driver.core.Id("userId-001"), - state = PatientHistory.State.Verify, - action = PatientHistory.Action.Start, - created = LocalDateTime.parse("2017-08-10T18:00:00") - ) - val writtenJson = patientHistoryFormat.write(patientHistory) - - writtenJson should be( - """{"id":10,"executor":"userId-001","patientId":"40892a07-c638-49d2-9795-1edfefbbcc7c","state":"Verify", - "action":"Start","created":"2017-08-10T18:00Z"}""".parseJson) - - val parsedPatientHistory = patientHistoryFormat.read(writtenJson) - parsedPatientHistory should be(patientHistory) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientHypothesisFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientHypothesisFormatSuite.scala deleted file mode 100644 index 560b1b6..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientHypothesisFormatSuite.scala +++ /dev/null @@ -1,28 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import eu.timepit.refined.numeric.NonNegative -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuicommon.domain.UuidId -import xyz.driver.pdsuidomain.entities.PatientHypothesis -import eu.timepit.refined.refineMV - -class PatientHypothesisFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.patienthypothesis._ - - "Json format for patientHypothesis" should "read and write correct JSON" in { - val orig = PatientHypothesis( - id = UuidId("815d9715-1089-4775-b120-3afb983b9a97"), - patientId = UuidId("748b5884-3528-4cb9-904b-7a8151d6e343"), - hypothesisId = UuidId("e76e2fc4-a29c-44fb-a81b-8856d06bb1d4"), - rationale = None, - matchedTrials = refineMV[NonNegative](1) - ) - val writtenJson = patientHypothesisWriter.write(orig) - - writtenJson should be( - """{"id":"815d9715-1089-4775-b120-3afb983b9a97","patientId":"748b5884-3528-4cb9-904b-7a8151d6e343", - "hypothesisId":"e76e2fc4-a29c-44fb-a81b-8856d06bb1d4","rationale":null,"matchedTrials":1}""".parseJson) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientIssueFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientIssueFormatSuite.scala deleted file mode 100644 index ee76094..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientIssueFormatSuite.scala +++ /dev/null @@ -1,45 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuidomain.entities.PatientIssue - -class PatientIssueFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.patientissue._ - - "Json format for PatientIssue" should "read and write correct JSON" in { - val patientIssue = PatientIssue( - id = LongId(10), - patientId = UuidId("40892a07-c638-49d2-9795-1edfefbbcc7c"), - userId = xyz.driver.core.Id("userId-001"), - lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00"), - isDraft = false, - text = "message text", - archiveRequired = false - ) - val writtenJson = patientIssueWriter.write(patientIssue) - - writtenJson should be("""{"id":10,"userId":"userId-001","lastUpdate":"2017-08-10T18:00Z","isDraft":false, - "text":"message text","archiveRequired":false}""".parseJson) - - val createPatientIssueJson = """{"text":"message text"}""".parseJson - val expectedCreatedPatientIssue = patientIssue.copy(id = LongId(0), lastUpdate = LocalDateTime.MIN, isDraft = true) - val parsedCreatePatientIssue = jsValueToPatientIssue(createPatientIssueJson, - UuidId("40892a07-c638-49d2-9795-1edfefbbcc7c"), - xyz.driver.core.Id("userId-001")) - parsedCreatePatientIssue should be(expectedCreatedPatientIssue) - - val updatePatientIssueJson = - """{"text":"new issue text","evidence":"issue evidence","archiveRequired":true}""".parseJson - val expectedUpdatedPatientIssue = patientIssue.copy( - text = "new issue text", - archiveRequired = true - ) - val parsedUpdatePatientIssue = applyUpdateToPatientIssue(updatePatientIssueJson, patientIssue) - parsedUpdatePatientIssue should be(expectedUpdatedPatientIssue) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientLabelFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientLabelFormatSuite.scala deleted file mode 100644 index 9340d02..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/PatientLabelFormatSuite.scala +++ /dev/null @@ -1,78 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDate - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.entities.labels.LabelValue -import xyz.driver.pdsuicommon.domain.{LongId, UuidId} -import xyz.driver.pdsuidomain.entities._ - -class PatientLabelFormatSuite extends FlatSpec with Matchers { - - "Json format for RichPatientLabel" should "read and write correct JSON" in { - import xyz.driver.pdsuidomain.formats.json.patientlabel._ - val orig = PatientLabel( - id = LongId(1), - patientId = UuidId("748b5884-3528-4cb9-904b-7a8151d6e343"), - labelId = LongId(20), - primaryValue = LabelValue.Yes, - verifiedPrimaryValue = LabelValue.Unknown, - isVisible = true, - score = 1, - isImplicitMatch = false - ) - val writtenJson = richPatientLabelFormat.write(RichPatientLabel(orig, isVerified = true)) - - writtenJson should be( - """{"id":1,"labelId":20,"primaryValue":"Yes","isVisible":true,"isVerified":true,"verifiedPrimaryValue":"Unknown", - "score":1,"isImplicitMatch":false, "patientId":"748b5884-3528-4cb9-904b-7a8151d6e343"}""".parseJson) - - val updatePatientLabelJson = """{"verifiedPrimaryValue":"No"}""".parseJson - val expectedUpdatedPatientLabel = orig.copy(verifiedPrimaryValue = LabelValue.No) - val parsedUpdatePatientLabel = applyUpdateToPatientLabel(updatePatientLabelJson, orig) - parsedUpdatePatientLabel should be(expectedUpdatedPatientLabel) - } - - "Json format for PatientLabelEvidence" should "read and write correct JSON" in { - import xyz.driver.pdsuidomain.formats.json.patientlabel._ - val orig = PatientLabelEvidenceView( - id = LongId(1), - value = LabelValue.Maybe, - evidenceText = "evidence text", - documentId = Some(LongId(21)), - evidenceId = Some(LongId(10)), - reportId = None, - documentType = DocumentType.LaboratoryReport, - date = Some(LocalDate.parse("2017-08-10")), - providerType = ProviderType.EmergencyMedicine, - patientId = UuidId("748b5884-3528-4cb9-904b-7a8151d6e343"), - labelId = LongId(20), - isImplicitMatch = false - ) - val writtenJson = patientLabelEvidenceWriter.write(orig) - - writtenJson should be( - """{"id":1,"value":"Maybe","evidenceText":"evidence text","documentId":21,"evidenceId":10,"reportId":null, - "documentType":{"id":3,"name":"Laboratory Report"},"date":"2017-08-10", - "providerType":{"id":26,"name":"Emergency Medicine"}}""".parseJson) - } - - "Json format for PatientLabelDefiningCriteria" should "read and write correct JSON" in { - import xyz.driver.pdsuidomain.formats.json.patientdefiningcriteria._ - val orig = PatientLabel( - id = LongId(1), - patientId = UuidId("748b5884-3528-4cb9-904b-7a8151d6e343"), - labelId = LongId(20), - primaryValue = LabelValue.Yes, - verifiedPrimaryValue = LabelValue.Yes, - isVisible = true, - score = 1, - isImplicitMatch = false - ) - val writtenJson = patientLabelDefiningCriteriaWriter.write(orig) - - writtenJson should be("""{"id":1,"value":"Yes"}""".parseJson) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/SlotArmFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/SlotArmFormatSuite.scala deleted file mode 100644 index 95853f6..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/SlotArmFormatSuite.scala +++ /dev/null @@ -1,36 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities.SlotArm - -class SlotArmFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.slotarm._ - - "Json format for SlotArm" should "read and write correct JSON" in { - val arm = SlotArm( - id = LongId(10), - trialId = StringId("NCT000001"), - name = "arm name", - originalName = "orig arm name" - ) - val writtenJson = slotArmFormat.write(arm) - - writtenJson should be( - """{"id":10,"trialId":"NCT000001","name":"arm name","originalName":"orig arm name"}""".parseJson) - - val createArmJson = """{"trialId":"NCT000001","name":"arm name"}""".parseJson - val parsedArm = slotArmFormat.read(createArmJson) - val expectedCreatedArm = arm.copy( - id = LongId(0), - originalName = "arm name" - ) - parsedArm should be(expectedCreatedArm) - - val updateArmJson = """{"name":"new arm name"}""".parseJson - val expectedUpdatedArm = arm.copy(name = "new arm name") - val parsedUpdateArm = applyUpdateToArm(updateArmJson, arm) - parsedUpdateArm should be(expectedUpdatedArm) - } -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/StudyDesignFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/StudyDesignFormatSuite.scala deleted file mode 100644 index f3a4c83..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/StudyDesignFormatSuite.scala +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuidomain.entities.StudyDesign - -class StudyDesignFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.studydesign._ - - "Json format for StudyDesign" should "read and write correct JSON" in { - val studyDesign = StudyDesign.Randomized - val writtenJson = studyDesignFormat.write(studyDesign) - - writtenJson should be("""{"id":1,"name":"Randomized"}""".parseJson) - - val parsedStudyDesign = studyDesignFormat.read(writtenJson) - parsedStudyDesign should be(studyDesign) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialFormatSuite.scala deleted file mode 100644 index b832733..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialFormatSuite.scala +++ /dev/null @@ -1,49 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import org.scalatest.{FlatSpec, Matchers} -import spray.json._ -import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} -import xyz.driver.pdsuidomain.entities.Trial - -class TrialFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.trial._ - - "Json format for Trial" should "read and write correct JSON" in { - val orig = Trial( - id = StringId("NCT000001"), - externalId = UuidId("40892a07-c638-49d2-9795-1edfefbbcc7c"), - status = Trial.Status.New, - assignee = None, - previousStatus = None, - previousAssignee = None, - lastActiveUserId = None, - lastUpdate = LocalDateTime.parse("2017-08-10T18:16:19"), - phase = "", - hypothesisId = Some(UuidId("3b80b2e2-5372-4cf5-a342-6e4ebe10fafd")), - studyDesignId = Some(LongId(321)), - originalStudyDesign = None, - isPartner = false, - overview = None, - overviewTemplate = "", - isUpdated = false, - title = "trial title", - originalTitle = "orig trial title" - ) - val writtenJson = trialFormat.write(orig) - - writtenJson should be( - """{"isPartner":false,"assignee":null,"lastUpdate":"2017-08-10T18:16:19Z","previousStatus":null, - "isUpdated":false,"overviewTemplate":"","phase":"","originalStudyDesignId":null, - "hypothesisId":"3b80b2e2-5372-4cf5-a342-6e4ebe10fafd","originalTitle":"orig trial title", - "studyDesignId":321,"lastActiveUser":null,"externalid":"40892a07-c638-49d2-9795-1edfefbbcc7c", - "id":"NCT000001","status":"New","overview":null,"previousAssignee":null,"title":"trial title"}""".parseJson) - - val updateTrialJson = """{"hypothesisId":null,"overview":"new overview"}""".parseJson - val expectedUpdatedTrial = orig.copy(hypothesisId = None, overview = Some("new overview")) - val parsedUpdateTrial = applyUpdateToTrial(updateTrialJson, orig) - parsedUpdateTrial should be(expectedUpdatedTrial) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialHistoryFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialHistoryFormatSuite.scala deleted file mode 100644 index 7f4f169..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialHistoryFormatSuite.scala +++ /dev/null @@ -1,32 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities.TrialHistory - -class TrialHistoryFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.trialhistory._ - - "Json format for TrialHistory" should "read and write correct JSON" in { - val trialHistory = TrialHistory( - id = LongId(10), - trialId = StringId("NCT000001"), - executor = xyz.driver.core.Id("userId-001"), - state = TrialHistory.State.Summarize, - action = TrialHistory.Action.Start, - created = LocalDateTime.parse("2017-08-10T18:00:00"), - comment = Option("Yolo!") - ) - val writtenJson = trialHistoryFormat.write(trialHistory) - - writtenJson should be("""{"id":10,"executor":"userId-001","trialId":"NCT000001","state":"Summarize", - "action":"Start","created":"2017-08-10T18:00Z", "comment": "Yolo!"}""".parseJson) - - val parsedTrialHistory = trialHistoryFormat.read(writtenJson) - parsedTrialHistory should be(trialHistory) - } - -} diff --git a/src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialIssueFormatSuite.scala b/src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialIssueFormatSuite.scala deleted file mode 100644 index a13e097..0000000 --- a/src/test/scala/xyz/driver/pdsuidomain/formats/json/TrialIssueFormatSuite.scala +++ /dev/null @@ -1,50 +0,0 @@ -package xyz.driver.pdsuidomain.formats.json - -import java.time.LocalDateTime - -import spray.json._ -import org.scalatest.{FlatSpec, Matchers} -import xyz.driver.pdsuicommon.domain.{LongId, StringId} -import xyz.driver.pdsuidomain.entities.TrialIssue - -class TrialIssueFormatSuite extends FlatSpec with Matchers { - import xyz.driver.pdsuidomain.formats.json.trialissue._ - - "Json format for TrialIssue" should "read and write correct JSON" in { - val trialIssue = TrialIssue( - id = LongId(10), - trialId = StringId("NCT000001"), - userId = xyz.driver.core.Id("userId-001"), - lastUpdate = LocalDateTime.parse("2017-08-10T18:00:00"), - isDraft = false, - text = "message text", - evidence = "evidence", - archiveRequired = false, - meta = "{}" - ) - val writtenJson = trialIssueWriter.write(trialIssue) - - writtenJson should be("""{"id":10,"userId":"userId-001","lastUpdate":"2017-08-10T18:00Z","isDraft":false, - "text":"message text","evidence":"evidence","archiveRequired":false,"meta":"{}"}""".parseJson) - trialIssueReader(StringId("NCT000001")).read(writtenJson) shouldBe trialIssue - - val createTrialIssueJson = """{"text":"message text","evidence":"evidence","meta":"{}"}""".parseJson - val expectedCreatedTrialIssue = trialIssue.copy(id = LongId(0), lastUpdate = LocalDateTime.MIN, isDraft = true) - val parsedCreateTrialIssue = - jsValueToTrialIssue(createTrialIssueJson, StringId("NCT000001"), xyz.driver.core.Id("userId-001")) - parsedCreateTrialIssue should be(expectedCreatedTrialIssue) - - val updateTrialIssueJson = - """{"text":"new issue text","evidence":"issue evidence","archiveRequired":true, - "meta":"{\"startPage\":1.0,\"endPage\":2.0}"}""".parseJson - val expectedUpdatedTrialIssue = trialIssue.copy( - text = "new issue text", - evidence = "issue evidence", - archiveRequired = true, - meta = """{"startPage":1.0,"endPage":2.0}""" - ) - val parsedUpdateTrialIssue = applyUpdateToTrialIssue(updateTrialIssueJson, trialIssue) - parsedUpdateTrialIssue should be(expectedUpdatedTrialIssue) - } - -} diff --git a/src/test/scala/xyz/driver/restquery/db/SearchFilterExprSuite.scala b/src/test/scala/xyz/driver/restquery/db/SearchFilterExprSuite.scala new file mode 100644 index 0000000..35c8d30 --- /dev/null +++ b/src/test/scala/xyz/driver/restquery/db/SearchFilterExprSuite.scala @@ -0,0 +1,34 @@ +package xyz.driver.pdsuicommon.db + +import org.scalatest.{FreeSpecLike, MustMatchers} + +class SearchFilterExprSuite extends FreeSpecLike with MustMatchers { + + "replace" - { + "all entities are changed" in { + val ast = SearchFilterExpr.Union( + Seq( + SearchFilterExpr.Intersection( + Seq( + SearchFilterExpr.Atom.Binary("foo", SearchFilterBinaryOperation.Gt, "10"), + SearchFilterExpr.Atom.Binary("foo", SearchFilterBinaryOperation.Lt, "20") + )), + SearchFilterExpr.Atom.NAry("bar", SearchFilterNAryOperation.In, Seq("x", "y", "z")), + SearchFilterExpr.Atom.Binary("foo", SearchFilterBinaryOperation.Eq, "40") + )) + + val newAst = ast.replace { + case x: SearchFilterExpr.Atom.Binary if x.dimension.name == "foo" => + x.copy(dimension = x.dimension.copy(name = "bar")) + } + + val result = newAst.find { + case x: SearchFilterExpr.Atom.Binary => x.dimension.name == "foo" + case _ => false + } + + result mustBe empty + } + } + +} diff --git a/src/test/scala/xyz/driver/restquery/rest/parsers/PaginationParserSuite.scala b/src/test/scala/xyz/driver/restquery/rest/parsers/PaginationParserSuite.scala new file mode 100644 index 0000000..c753480 --- /dev/null +++ b/src/test/scala/xyz/driver/restquery/rest/parsers/PaginationParserSuite.scala @@ -0,0 +1,103 @@ +package xyz.driver.restquery.http.parsers + +import xyz.driver.restquery.http.parsers.TestUtils._ +import org.scalatest.{FreeSpecLike, MustMatchers} +import xyz.driver.restquery.domain.Pagination + +import scala.util.{Failure, Try} + +class PaginationParserSuite extends FreeSpecLike with MustMatchers { + + "parse" - { + "pageSize" - { + "should parse positive value" in { + val pagination = PaginationParser.parse( + Seq( + "pageSize" -> "10", + "pageNumber" -> "1" + )) + pagination must success + pagination.get.pageSize mustBe 10 + } + + "should return a default value if there is no one" in { + val pagination = PaginationParser.parse( + Seq( + "pageNumber" -> "1" + )) + pagination must success + pagination.get.pageSize mustBe 100 + } + + "should return a error for zero value" in { + val pagination = PaginationParser.parse( + Seq( + "pageSize" -> "0", + "pageNumber" -> "1" + )) + + checkFailedValidationOnlyOn(pagination, "pageSize") + } + + "should return a error for negative value" in { + val pagination = PaginationParser.parse( + Seq( + "pageSize" -> "-10", + "pageNumber" -> "1" + )) + + checkFailedValidationOnlyOn(pagination, "pageSize") + } + } + + "pageNumber" - { + "should parse positive value" in { + val pagination = PaginationParser.parse( + Seq( + "pageSize" -> "1", + "pageNumber" -> "1" + )) + pagination must success + pagination.get.pageSize mustBe 1 + } + + "should return a default value if there is no one" in { + val pagination = PaginationParser.parse( + Seq( + "pageSize" -> "1" + )) + pagination must success + pagination.get.pageNumber mustBe 1 + } + + "should return a error for zero value" in { + val pagination = PaginationParser.parse( + Seq( + "pageSize" -> "1", + "pageNumber" -> "0" + )) + + checkFailedValidationOnlyOn(pagination, "pageNumber") + } + + "should return a error for negative value" in { + val pagination = PaginationParser.parse( + Seq( + "pageSize" -> "1", + "pageNumber" -> "-1" + )) + + checkFailedValidationOnlyOn(pagination, "pageNumber") + } + } + } + + private def checkFailedValidationOnlyOn(pagination: Try[Pagination], key: String): Unit = { + pagination must failWith[ParseQueryArgException] + + val Failure(e: ParseQueryArgException) = pagination + e.errors.size mustBe 1 + e.errors.head._1 mustBe key + } + +} diff --git a/src/test/scala/xyz/driver/restquery/rest/parsers/SearchFilterParserSuite.scala b/src/test/scala/xyz/driver/restquery/rest/parsers/SearchFilterParserSuite.scala new file mode 100644 index 0000000..efa8666 --- /dev/null +++ b/src/test/scala/xyz/driver/restquery/rest/parsers/SearchFilterParserSuite.scala @@ -0,0 +1,259 @@ +package xyz.driver.restquery.http.parsers + +import java.util.UUID + +import fastparse.core.Parsed +import org.scalacheck.Arbitrary.arbitrary +import org.scalacheck.{Gen, Prop} +import org.scalatest.FreeSpecLike +import org.scalatest.prop.Checkers +import xyz.driver.restquery.domain.SearchFilterBinaryOperation.Eq +import xyz.driver.restquery.domain.SearchFilterExpr.Dimension +import xyz.driver.restquery.domain.SearchFilterNAryOperation.In +import xyz.driver.restquery.domain.{SearchFilterExpr, SearchFilterNAryOperation} +import xyz.driver.restquery.http.parsers.TestUtils._ +import xyz.driver.restquery.utils.Utils +import xyz.driver.restquery.utils.Utils._ + +import scala.util._ + +object SearchFilterParserSuite { + + class UnexpectedSearchFilterExprException(x: SearchFilterExpr) extends Exception(s"unexpected $x") + +} + +class SearchFilterParserSuite extends FreeSpecLike with Checkers { + + import SearchFilterParserSuite._ + + "parse" - { + "should convert column names to snake case" in { + import xyz.driver.restquery.domain.SearchFilterBinaryOperation._ + + val filter = SearchFilterParser.parse( + Seq( + "filters" -> "status IN Summarized,ReviewCriteria,Flagged,Done", + "filters" -> "previousStatus NOTEQ New", + "filters" -> "previousStatus NOTEQ ReviewSummary" + )) + + assert( + filter === Success(SearchFilterExpr.Intersection(List( + SearchFilterExpr.Atom + .NAry(Dimension(None, "status"), In, Seq("Summarized", "ReviewCriteria", "Flagged", "Done")), + SearchFilterExpr.Atom.Binary(Dimension(None, "previous_status"), NotEq, "New"), + SearchFilterExpr.Atom.Binary(Dimension(None, "previous_status"), NotEq, "ReviewSummary") + )))) + } + "dimensions" - { + "with table name" in check { + val dimensionGen = { + for (left <- Gen.identifier; right <- Gen.identifier) + yield left -> right + } + Prop.forAllNoShrink(dimensionGen) { + case (left, right) => + val raw = s"$left.$right" + val l = toSnakeCase(left) + val r = toSnakeCase(right) + SearchFilterParser.dimensionParser.parse(raw) match { + case Parsed.Success(Dimension(Some(`l`), `r`), _) => true + case _ => false + } + } + } + "just with field name" in check { + Prop.forAllNoShrink(Gen.identifier) { s => + val databaseS = Utils.toSnakeCase(s) + SearchFilterParser.dimensionParser.parse(s) match { + case Parsed.Success(Dimension(None, `databaseS`), _) => true + case _ => false + } + } + } + } + "atoms" - { + "binary" - { + "common operators" - { + "should be parsed with text values" in check { + import xyz.driver.restquery.domain.SearchFilterBinaryOperation._ + + val testQueryGen = queryGen( + dimensionGen = Gen.identifier, + opGen = commonBinaryOpsGen, + valueGen = nonEmptyString + ) + + Prop.forAllNoShrink(testQueryGen) { query => + SearchFilterParser + .parse(Seq("filters" -> query)) + .map { + case SearchFilterExpr.Atom.Binary(_, Eq | NotEq | Like, _) => true + case x => throw new UnexpectedSearchFilterExprException(x) + } + .successProp + } + } + } + + "numeric operators" - { + "should not be parsed with text values" in check { + val testQueryGen = queryGen( + dimensionGen = Gen.identifier, + opGen = numericBinaryOpsGen, + valueGen = nonEmptyString.filter { s => + !s.matches("^\\d+$") + } + ) + + Prop.forAllNoShrink(testQueryGen) { query => + SearchFilterParser.parse(Seq("filters" -> query)).failureProp + } + } + } + + "actual recordId" - { + "should not be parsed with numeric values" in { + val filter = SearchFilterParser.parse(Seq("filters" -> "recordId EQ 1")) + assert(filter === Success(SearchFilterExpr.Atom.Binary(Dimension(None, "record_id"), Eq, Long.box(1)))) + } + } + + "actual isVisible boolean" - { + "should not be parsed with boolean values" in { + val filter = SearchFilterParser.parse(Seq("filters" -> "isVisible EQ true")) + assert(filter === Success(SearchFilterExpr.Atom.Binary(Dimension(None, "is_visible"), Eq, Boolean.box(true)))) + } + } + + "actual patientId uuid" - { + "should parse the full UUID as java.util.UUID type" in { + val filter = SearchFilterParser.parse(Seq("filters" -> "patientId EQ 4b4879f7-42b3-4b7c-a685-5c97d9e69e7c")) + assert(filter === Success(SearchFilterExpr.Atom.Binary( + Dimension(None, "patient_id"), Eq, UUID.fromString("4b4879f7-42b3-4b7c-a685-5c97d9e69e7c")))) + } + } + + "all operators" - { + "should be parsed with numeric values" in check { + val testQueryGen = queryGen( + dimensionGen = Gen.identifier, + opGen = allBinaryOpsGen, + valueGen = numericBinaryAtomValuesGen + ) + + Prop.forAllNoShrink(testQueryGen) { query => + SearchFilterParser + .parse(Seq("filters" -> query)) + .map { + case _: SearchFilterExpr.Atom.Binary => true + case x => throw new UnexpectedSearchFilterExprException(x) + } + .successProp + } + } + } + } + + "n-ary" - { + "actual record Ids" - { + "should not be parsed with text values" in { + val filter = SearchFilterParser.parse(Seq("filters" -> "id IN 1,5")) + filter match { + case Success(_) => () + case Failure(t) => t.printStackTrace() + } + assert( + filter === Success(SearchFilterExpr.Atom.NAry(Dimension(None, "id"), In, Seq(Long.box(1), Long.box(5))))) + } + } + + "in" in check { + val testQueryGen = queryGen( + dimensionGen = Gen.identifier, + opGen = Gen.const("in"), + valueGen = inValuesGen + ) + + Prop.forAllNoShrink(testQueryGen) { query => + SearchFilterParser + .parse(Seq("filters" -> query)) + .map { + case SearchFilterExpr.Atom.NAry(_, SearchFilterNAryOperation.In, _) => true + case x => throw new UnexpectedSearchFilterExprException(x) + } + .successProp + } + } + } + } + + "intersections" - { + "should be parsed" in check { + val commonAtomsGen = queryGen( + dimensionGen = Gen.identifier, + opGen = commonBinaryOpsGen, + valueGen = nonEmptyString + ) + + val numericAtomsGen = queryGen( + dimensionGen = Gen.identifier, + opGen = numericBinaryOpsGen, + valueGen = numericBinaryAtomValuesGen + ) + + val allAtomsGen = Gen.oneOf(commonAtomsGen, numericAtomsGen) + val intersectionsGen = Gen.choose(1, 3).flatMap { size => + Gen.containerOfN[Seq, String](size, allAtomsGen) + } + + Prop.forAllNoShrink(intersectionsGen) { queries => + SearchFilterParser.parse(queries.map(query => "filters" -> query)).successProp + } + } + } + } + + private val CommonBinaryOps = Seq("eq", "noteq", "like") + private val NumericBinaryOps = Seq("gt", "gteq", "lt", "lteq") + + private val allBinaryOpsGen: Gen[String] = + Gen.oneOf(CommonBinaryOps ++ NumericBinaryOps).flatMap(randomCapitalization) + private val commonBinaryOpsGen: Gen[String] = Gen.oneOf(CommonBinaryOps).flatMap(randomCapitalization) + private val numericBinaryOpsGen: Gen[String] = Gen.oneOf(NumericBinaryOps).flatMap(randomCapitalization) + + private val inValueCharsGen: Gen[Char] = arbitrary[Char].filter(_ != ',') + + private val nonEmptyString = arbitrary[String].filter { s => + !Utils.safeTrim(s).isEmpty + } + + private val numericBinaryAtomValuesGen: Gen[String] = arbitrary[Long].map(_.toString) + private val inValueGen: Gen[String] = { + Gen.nonEmptyContainerOf[Seq, Char](inValueCharsGen).map(_.mkString).filter(s => Utils.safeTrim(s).nonEmpty) + } + private val inValuesGen: Gen[String] = Gen.choose(1, 5).flatMap { size => + Gen.containerOfN[Seq, String](size, inValueGen).map(_.mkString(",")) + } + + private def queryGen(dimensionGen: Gen[String], opGen: Gen[String], valueGen: Gen[String]): Gen[String] = + for { + dimension <- dimensionGen + op <- opGen + value <- valueGen + } yield s"$dimension $op $value" + + private def randomCapitalization(input: String): Gen[String] = { + Gen.containerOfN[Seq, Boolean](input.length, arbitrary[Boolean]).map { capitalize => + input.view + .zip(capitalize) + .map { + case (currChar, true) => currChar.toUpper + case (currChar, false) => currChar + } + .mkString + } + } + +} diff --git a/src/test/scala/xyz/driver/restquery/rest/parsers/SortingParserSuite.scala b/src/test/scala/xyz/driver/restquery/rest/parsers/SortingParserSuite.scala new file mode 100644 index 0000000..1813181 --- /dev/null +++ b/src/test/scala/xyz/driver/restquery/rest/parsers/SortingParserSuite.scala @@ -0,0 +1,96 @@ +package xyz.driver.restquery.http.parsers + +import xyz.driver.restquery.http.parsers.TestUtils._ +import org.scalacheck.Arbitrary.arbitrary +import org.scalacheck.{Gen, Prop} +import org.scalatest.prop.Checkers +import org.scalatest.{FreeSpecLike, MustMatchers} + +class SortingParserSuite extends FreeSpecLike with MustMatchers with Checkers { + + "parse" - { + "single dimension" - commonTests(singleSortingQueryGen) + "multiple dimensions in one query" - commonTests(multipleSortingQueryGen) + "multiple queries" in { + val r = SortingParser.parse(Set("foo", "bar"), Seq("sort" -> "foo", "sort" -> "bar")) + r must failWith[ParseQueryArgException] + } + } + + private def commonTests(queryGen: Set[String] => Gen[String]): Unit = { + "valid" in check { + val inputGen: Gen[(Set[String], String)] = for { + validDimensions <- dimensionsGen + sorting <- queryGen(validDimensions) + } yield (validDimensions, sorting) + + Prop.forAllNoShrink(inputGen) { + case (validDimensions, query) => + SortingParser.parse(validDimensions, Seq("sort" -> query)).successProp + } + } + + "invalid" in check { + val inputGen: Gen[(Set[String], String)] = for { + validDimensions <- dimensionsGen + invalidDimensions <- dimensionsGen.filter { xs => + xs.intersect(validDimensions).isEmpty + } + sorting <- queryGen(invalidDimensions) + } yield (validDimensions, sorting) + + Prop.forAllNoShrink(inputGen) { + case (validDimensions, query) => + SortingParser.parse(validDimensions, Seq("sort" -> query)).failureProp + } + } + } + + private val dimensionsGen: Gen[Set[String]] = for { + unPrefixedSize <- Gen.choose(0, 3) + prefixedSize <- Gen.choose(0, 3) + if (unPrefixedSize + prefixedSize) > 0 + + unPrefixedDimensions <- Gen.containerOfN[Set, String](unPrefixedSize, Gen.identifier) + + prefixes <- Gen.containerOfN[Set, String](prefixedSize, Gen.identifier) + dimensions <- Gen.containerOfN[Set, String](prefixedSize, Gen.identifier) + } yield { + val prefixedDimensions = prefixes.zip(dimensions).map { + case (prefix, dimension) => s"$prefix.$dimension" + } + unPrefixedDimensions ++ prefixedDimensions + } + + private def multipleSortingQueryGen(validDimensions: Set[String]): Gen[String] = { + val validDimensionsSeq = validDimensions.toSeq + val indexGen = Gen.oneOf(validDimensionsSeq.indices) + val multipleDimensionsGen = Gen.nonEmptyContainerOf[Set, Int](indexGen).filter(_.size >= 2).map { indices => + indices.map(validDimensionsSeq.apply) + } + + for { + dimensions <- multipleDimensionsGen + isAscending <- Gen.containerOfN[Seq, Boolean](dimensions.size, arbitrary[Boolean]) + } yield { + isAscending + .zip(dimensions) + .map { + case (true, dimension) => dimension + case (false, dimension) => "-" + dimension + } + .mkString(",") + } + } + + private def singleSortingQueryGen(validDimensions: Set[String]): Gen[String] = + for { + isAscending <- arbitrary[Boolean] + dimensions <- Gen.oneOf(validDimensions.toSeq) + } yield + isAscending match { + case true => dimensions + case false => "-" + dimensions + } + +} diff --git a/src/test/scala/xyz/driver/restquery/rest/parsers/TestUtils.scala b/src/test/scala/xyz/driver/restquery/rest/parsers/TestUtils.scala new file mode 100644 index 0000000..9ea75b6 --- /dev/null +++ b/src/test/scala/xyz/driver/restquery/rest/parsers/TestUtils.scala @@ -0,0 +1,54 @@ +package xyz.driver.restquery.http.parsers + +import +org.scalacheck.Prop +import org.scalacheck.Prop.BooleanOperators +import org.scalatest.matchers.{MatchResult, Matcher} +import xyz.driver.restquery.utils.Utils + +import scala.reflect.ClassTag +import scala.util.{Failure, Success, Try} + +object TestUtils { + + object success extends Matcher[Try[Any]] { + override def apply(left: Try[Any]) = { + MatchResult(left.isSuccess, s"$left did not fail", s"did fail with $left") + } + } + + class FailWith[ThrowableT <: Throwable](implicit ct: ClassTag[ThrowableT]) extends Matcher[Try[Any]] { + override def apply(left: Try[Any]): MatchResult = { + MatchResult( + left.isFailure && left.failed.get.getClass == ct.runtimeClass, + left match { + case Success(_) => s"$left did not fail" + case Failure(e) => + s"$left did fail with ${Utils.getClassSimpleName(e.getClass)}, " + + s"not ${Utils.getClassSimpleName(ct.runtimeClass)}" + }, + left match { + case Success(_) => s"$left failed with ${Utils.getClassSimpleName(ct.runtimeClass)}" + case Failure(e) => s"$left failed with ${Utils.getClassSimpleName(e.getClass)}" + } + ) + } + } + + def failWith[ThrowableT <: Throwable](implicit ct: ClassTag[ThrowableT]) = new FailWith[ThrowableT] + + final implicit class TryPropOps(val self: Try[Any]) extends AnyVal { + + def successProp: Prop = self match { + case Success(_) => true :| "ok" + case Failure(e) => false :| e.getMessage + } + + def failureProp: Prop = self match { + case Success(x) => false :| s"invalid: $x" + case Failure(_) => true + } + + } + +} diff --git a/src/test/scala/xyz/driver/restquery/utils/StringOpsSuite.scala b/src/test/scala/xyz/driver/restquery/utils/StringOpsSuite.scala new file mode 100644 index 0000000..bd0bd2b --- /dev/null +++ b/src/test/scala/xyz/driver/restquery/utils/StringOpsSuite.scala @@ -0,0 +1,33 @@ +package xyz.driver.pdsuicommon.utils + +import xyz.driver.pdsuicommon.utils.Implicits.toStringOps +import org.scalatest.FreeSpecLike + +class StringOpsSuite extends FreeSpecLike { + + "safeTrim" - { + "empty string" in { + assert("".safeTrim == "") + } + + "string with whitespace symbols" in { + assert("\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000".safeTrim == "") + } + + "string with control symbols" in { + assert("\u001f\u007f\t\n".safeTrim == "") + } + + "whitespaces and control symbols from the left side" in { + assert("\u001f\u2002\u007f\nfoo".safeTrim == "foo") + } + + "whitespaces and control symbols from the right side" in { + assert("foo\u001f\u2002\u007f\n".safeTrim == "foo") + } + + "already trimmed string" in { + assert("foo".safeTrim == "foo") + } + } +} -- cgit v1.2.3