use of org.hl7.fhir.r5.model.DataType in project quality-measure-and-cohort-service by Alvearie.
the class CohortEngineRestHandler method evaluatePatientListMeasure.
@POST
@Path("/evaluation-patient-list")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces({ MediaType.APPLICATION_JSON })
@ApiOperation(value = "Evaluates a measure bundle for a list of patients", notes = EVALUATION_API_NOTES, response = String.class, tags = { "Measure Evaluation" }, extensions = { @Extension(properties = { @ExtensionProperty(name = DarkFeatureSwaggerFilter.DARK_FEATURE_NAME, value = CohortEngineRestConstants.DARK_LAUNCHED_PATIENT_LIST_MEASURE_EVALUATION) }) })
@ApiImplicitParams({ // This is necessary for the dark launch feature
@ApiImplicitParam(access = DarkFeatureSwaggerFilter.DARK_FEATURE_CONTROLLED, paramType = "header", dataType = "string"), // These are necessary to create a proper view of the request body that is all wrapped up in the Liberty IMultipartBody parameter
@ApiImplicitParam(name = REQUEST_DATA_PART, value = EXAMPLE_PATIENT_LIST_MEASURE_REQUEST_DATA_JSON, dataTypeClass = PatientListMeasureEvaluation.class, required = true, paramType = "form", type = "file"), @ApiImplicitParam(name = MEASURE_PART, value = EXAMPLE_MEASURE_ZIP, dataTypeClass = File.class, required = true, paramType = "form", type = "file") })
@ApiResponses(value = { @ApiResponse(code = 200, message = "Successful Operation: This API returns the JSON representation of a FHIR MeasureReport. A full example can be found at https://www.hl7.org/fhir/measurereport-cms146-cat2-example.html"), @ApiResponse(code = 400, message = "Bad Request", response = ServiceErrorList.class), @ApiResponse(code = 500, message = "Server Error", response = ServiceErrorList.class) })
public Response evaluatePatientListMeasure(@Context HttpServletRequest request, @ApiParam(value = ServiceBaseConstants.MINOR_VERSION_DESCRIPTION, required = true, defaultValue = ServiceBuildConstants.DATE) @QueryParam(CohortEngineRestHandler.VERSION) String version, @ApiParam(hidden = true, type = "file", required = true) IMultipartBody multipartBody) {
final String methodName = MethodNames.EVALUATE_PATIENT_LIST_MEASURE.getName();
Response response = null;
// Error out if feature is not enabled
ServiceBaseUtility.isDarkFeatureEnabled(CohortEngineRestConstants.DARK_LAUNCHED_PATIENT_LIST_MEASURE_EVALUATION);
try {
// Perform api setup
Response errorResponse = ServiceBaseUtility.apiSetup(version, logger, methodName);
if (errorResponse != null) {
return errorResponse;
}
if (multipartBody == null) {
throw new IllegalArgumentException("A multipart/form-data body is required");
}
IAttachment metadataAttachment = multipartBody.getAttachment(REQUEST_DATA_PART);
if (metadataAttachment == null) {
throw new IllegalArgumentException(String.format("Missing '%s' MIME attachment", REQUEST_DATA_PART));
}
IAttachment measureAttachment = multipartBody.getAttachment(MEASURE_PART);
if (measureAttachment == null) {
throw new IllegalArgumentException(String.format("Missing '%s' MIME attachment", MEASURE_PART));
}
// deserialize the PatientListMeasureEvaluation request
ObjectMapper om = new ObjectMapper();
PatientListMeasureEvaluation evaluationRequest = om.readValue(metadataAttachment.getDataHandler().getInputStream(), PatientListMeasureEvaluation.class);
// validate the contents of the evaluationRequest
validateBean(evaluationRequest);
FhirContext fhirContext = FhirContext.forR4();
try (InputStream is = measureAttachment.getDataHandler().getInputStream();
RetrieveCacheContext retrieveCacheContext = new DefaultRetrieveCacheContext()) {
MeasureEvaluator evaluator = createMeasureEvaluator(is, evaluationRequest.getDataServerConfig(), evaluationRequest.getTerminologyServerConfig(), evaluationRequest.isExpandValueSets(), evaluationRequest.getSearchPageSize(), retrieveCacheContext, fhirContext);
MeasureReport report = evaluator.evaluatePatientListMeasure(evaluationRequest.getPatientIds(), evaluationRequest.getMeasureContext(), evaluationRequest.getEvidenceOptions());
// The default serializer gets into an infinite loop when trying to serialize MeasureReport, so we use the
// HAPI encoder instead.
IParser parser = fhirContext.newJsonParser();
ResponseBuilder responseBuilder = Response.status(Response.Status.OK).header("Content-Type", "application/json").entity(parser.encodeResourceToString(report));
response = responseBuilder.build();
}
} catch (Throwable e) {
// map any exceptions caught into the proper REST error response objects
response = new CohortServiceExceptionMapper().toResponse(e);
} finally {
// Perform api cleanup
Response errorResponse = ServiceBaseUtility.apiCleanup(logger, methodName);
if (errorResponse != null) {
response = errorResponse;
}
}
return response;
}
use of org.hl7.fhir.r5.model.DataType in project quality-measure-and-cohort-service by Alvearie.
the class SparkSchemaCreator method getDataTypeForContextKey.
private Tuple2<String, DataType> getDataTypeForContextKey(String contextName, Set<Tuple2<String, String>> usingInfos) {
ContextDefinition contextDefinition = contextDefinitions.getContextDefinitionByName(contextName);
String primaryDataType = contextDefinition.getPrimaryDataType();
String primaryKeyColumn = contextDefinition.getPrimaryKeyColumn();
DataType keyType = null;
ModelManager modelManager = translator.newModelManager();
// Try to find the key column's type information from a single model info.
for (Tuple2<String, String> usingInfo : usingInfos) {
VersionedIdentifier modelInfoIdentifier = new VersionedIdentifier().withId(usingInfo._1()).withVersion(usingInfo._2());
ModelInfo modelInfo = modelManager.getModelInfoLoader().getModelInfo(modelInfoIdentifier);
// Look for a ClassInfo element matching primaryDataType for the context
List<ClassInfo> classInfos = getClassInfos(primaryDataType, modelInfo);
if (!classInfos.isEmpty()) {
if (classInfos.size() == 1) {
ClassInfo classInfo = classInfos.get(0);
List<ClassInfoElement> elements = classInfo.getElement().stream().filter(x -> x.getName().equals(primaryKeyColumn)).collect(Collectors.toList());
// check base type
String baseType = classInfo.getBaseType();
if (classInfo.getBaseType() != null) {
List<ClassInfo> baseClassInfos = getClassInfos(baseType, modelInfo);
baseClassInfos.stream().map(ClassInfo::getElement).flatMap(List::stream).filter(element -> element.getName().equals(primaryKeyColumn)).forEach(elements::add);
}
// check choice types
Collection<String> choiceTypes = ModelUtils.getChoiceTypeNames(classInfo);
choiceTypes.stream().map(type -> getClassInfos(type, modelInfo)).flatMap(List::stream).map(ClassInfo::getElement).flatMap(List::stream).filter(element -> element.getName().equals(primaryKeyColumn)).findFirst().ifPresent(elements::add);
// A future ModelInfo file may contain the information
if (elements.isEmpty()) {
continue;
} else if (elements.size() == 1) {
String elementType = elements.get(0).getElementType();
// store it
if (keyType == null) {
keyType = getSparkTypeForSystemValue(elementType);
} else {
throw new IllegalArgumentException("Multiple definitions found for " + primaryDataType + "." + primaryKeyColumn + " in the provided ModelInfo files. Cannot infer key type for context: " + contextName);
}
} else if (elements.size() > 1) {
throw new IllegalArgumentException("ModelInfo " + modelInfoIdentifier + " contains multiple element definitions for " + primaryKeyColumn + " for type " + primaryDataType);
}
} else {
throw new IllegalArgumentException("ModelInfo " + modelInfoIdentifier + " contains multiple definitions for type " + primaryDataType);
}
}
}
if (keyType == null) {
throw new IllegalArgumentException("Could not locate type information for " + primaryDataType + "." + primaryKeyColumn + " in the provided ModelInfo files. Cannot infer key type for context: " + contextName);
}
return new Tuple2<>(contextDefinition.getPrimaryKeyColumn(), keyType);
}
use of org.hl7.fhir.r5.model.DataType in project quality-measure-and-cohort-service by Alvearie.
the class SparkSchemaCreator method calculateSchemaForContext.
public StructType calculateSchemaForContext(String contextName) throws Exception {
List<CqlEvaluationRequest> filteredRequests = requests.getEvaluationsForContext(contextName);
StructType resultsSchema = new StructType();
Set<Tuple2<String, String>> usingInfo = new HashSet<>();
for (CqlEvaluationRequest filteredRequest : filteredRequests) {
CqlLibraryDescriptor descriptor = filteredRequest.getDescriptor();
String libraryId = descriptor.getLibraryId();
for (String expression : filteredRequest.getExpressionNames()) {
CqlLibrary providedLibrary = libraryProvider.getLibrary(new CqlLibraryDescriptor().setLibraryId(libraryId).setVersion(descriptor.getVersion()).setFormat(Format.ELM));
if (providedLibrary == null) {
throw new IllegalArgumentException("Library not found: " + descriptor.getLibraryId() + "-" + descriptor.getVersion());
}
Library library = CqlLibraryReader.read(providedLibrary.getContentAsStream());
// Track the set of non-system using statements across libraries.
// Information is used later to access ModelInfos when searching
// for context key column type information.
usingInfo.addAll(library.getUsings().getDef().stream().filter(x -> !x.getLocalIdentifier().equals("System")).map(x -> new Tuple2<>(x.getLocalIdentifier(), x.getVersion())).collect(Collectors.toList()));
List<ExpressionDef> expressionDefs = library.getStatements().getDef().stream().filter(x -> x.getName().equals(expression)).collect(Collectors.toList());
if (expressionDefs.isEmpty()) {
throw new IllegalArgumentException("Expression " + expression + " is configured in the CQL jobs file, but not found in " + descriptor.getLibraryId() + "-" + descriptor.getVersion());
} else if (expressionDefs.size() > 1) {
throw new IllegalArgumentException("Expression " + expression + " was defined multiple times in library: " + descriptor.getLibraryId() + "-" + descriptor.getVersion());
}
QName resultTypeName = expressionDefs.get(0).getExpression().getResultTypeName();
if (resultTypeName == null) {
throw new IllegalArgumentException("Expression " + expression + " has a null result type: " + descriptor.getLibraryId() + "-" + descriptor.getVersion());
}
// The column name encoder already performed duplicate checking. We just need to make sure
// we add each uniquely named column to the output one time.
String columnName = sparkOutputColumnEncoder.getColumnName(filteredRequest, expression);
if (resultsSchema.getFieldIndex(columnName).isEmpty()) {
resultsSchema = resultsSchema.add(columnName, QNameToDataTypeConverter.getFieldType(resultTypeName), true);
}
}
}
if (resultsSchema.fields().length > 0) {
Tuple2<String, DataType> keyInformation = getDataTypeForContextKey(contextName, usingInfo);
StructType fullSchema = new StructType().add(keyInformation._1(), keyInformation._2(), false).add(getParametersColumnName(), DataTypes.StringType, false);
for (StructField field : resultsSchema.fields()) {
fullSchema = fullSchema.add(field);
}
resultsSchema = fullSchema;
}
return resultsSchema;
}
use of org.hl7.fhir.r5.model.DataType in project quality-measure-and-cohort-service by Alvearie.
the class AnyColumnVisitor method visitFunctionRef.
@Override
public Object visitFunctionRef(FunctionRef elm, AnyColumnContext context) {
if (AnyColumnFunctions.FUNCTION_NAMES.contains(elm.getName())) {
if (elm.getOperand().size() == 2) {
QName dataType = ((As) elm.getOperand().get(0)).getOperand().getResultTypeName();
// TODO - validate that the first operand is a model object. We really should be doing that at the
// method declaration level instead of Choice<Any>, but that will require the model
// to have a base class that everything extends from.
String columnMatchLogic = null;
if (elm.getOperand().get(1) instanceof Literal) {
columnMatchLogic = ((Literal) elm.getOperand().get(1)).getValue();
} else {
throw new IllegalArgumentException(String.format("Second argument to %s function at %s must be a literal", elm.getName(), elm.getLocator()));
}
StringMatcher matcher = null;
if (elm.getName().equals(AnyColumnFunctions.FUNC_ANY_COLUMN)) {
matcher = new PrefixStringMatcher(columnMatchLogic);
} else if (elm.getName().equals(AnyColumnFunctions.FUNC_ANY_COLUMN_REGEX)) {
matcher = new RegexStringMatcher(columnMatchLogic);
} else {
throw new IllegalArgumentException(String.format("Found declared, but unsupported AnyColumn function %s at %s", elm.getName(), elm.getLocator()));
}
context.reportAnyColumn(dataType, matcher);
} else {
throw new IllegalArgumentException(String.format("%s function at %s should have exactly two arguments", elm.getName(), elm.getLocator()));
}
}
return super.visitFunctionRef(elm, context);
}
use of org.hl7.fhir.r5.model.DataType in project kindling by HL7.
the class TerminologyNotesGenerator method describeBinding.
public static String describeBinding(String prefix, BindingSpecification cd, PageProcessor page) throws Exception {
if (cd.getBinding() == BindingSpecification.BindingMethod.Unbound)
return cd.getDefinition();
if (cd.getBinding() == BindingSpecification.BindingMethod.Special) {
if (cd.getValueSet().getName().equals("MessageEvent"))
return "the <a href=\"" + prefix + "valueset-message-events.html\">Event List in the messaging framework</a>";
else if (cd.getValueSet().getName().equals("ResourceType"))
return "<a href=\"" + prefix + "valueset-resource-types.html\">Any defined Resource Type name</a>";
else if (cd.getValueSet().getName().equals("DataType"))
return "<a href=\"" + prefix + "valueset-data-types.html\">Any defined Data Type name</a>";
else if (cd.getValueSet().getName().equals("FHIRDefinedType"))
return "<a href=\"" + prefix + "valueset-defined-types.html\">Any defined Resource or Data Type name</a>";
else if (cd.getValueSet().getName().equals("FHIRAllTypes"))
return "<a href=\"" + prefix + "valueset-all-types.html\">Any defined Resource or Data Type name (including \"Any\" and \"Type\")</a>";
else
throw new Exception("Unknown special type " + cd.getValueSet().getName());
}
String mx = "";
if (cd.hasMax()) {
if (cd.getMaxValueSet() == null)
mx = " but limited to ??";
else {
String pp = cd.getMaxValueSet().hasUserData("external.url") ? cd.getMaxValueSet().getUserString("external.url") : cd.getMaxValueSet().getUserString("path");
mx = " but limited to <a href=\"" + prefix + pp.replace(File.separatorChar, '/') + "\">" + cd.getMaxValueSet().present() + "</a>";
}
}
String bs = "<a href=\"" + prefix + "terminologies.html#" + cd.getStrength().toCode() + "\">" + cd.getStrength().getDisplay() + "</a>";
if (cd.getValueSet() != null) {
ValueSet vs = cd.getValueSet();
String pp = vs.hasUserData("external.url") ? vs.getUserString("external.url") : vs.getUserString("path");
return "<a href=\"" + prefix + pp.replace(File.separatorChar, '/') + "\">" + cd.getValueSet().present() + "</a> (" + bs + mx + ")";
} else if (cd.getBinding() == BindingSpecification.BindingMethod.ValueSet) {
if (Utilities.noString(cd.getReference()))
return cd.getDescription();
else if (cd.getValueSet() == null)
return bs + ": <a href=\"" + (cd.getReference().startsWith("http") ? cd.getReference() : prefix + cd.getReference() + ".html") + "\">See " + cd.getDescription() + "</a> (" + cd.getDefinition() + mx + ")";
else
return bs + ": <a href=\"" + prefix + cd.getReference() + ".html\">See " + cd.getValueSet().getUrl() + "</a> (" + cd.getDefinition() + mx + ")";
} else if (cd.getBinding() == BindingSpecification.BindingMethod.CodeList) {
if (Utilities.noString(cd.getReference()))
return bs + ": " + cd.getDescription() + " (" + cd.getDefinition() + mx + ")";
else
return bs + ": <a href=\"" + prefix + "valueset-" + cd.getReference().substring(1) + ".html\">http://hl7.org/fhir/" + cd.getReference().substring(1) + "</a> (" + cd.getDefinition() + mx + ")";
}
return "??";
}
Aggregations