GraphQL Introspection Support (#3348)
* Start working on graphql Schema * Start testing * Work on introspection * Work on introspection * Use integers for date ordinals * Add changelog * GraphQL updates * Ongoing wrk * Cleanup * Bump core lib * Add changelog * Clean up dependencies * CLeanup * Add missing message * Test fix * Change to force CI
This commit is contained in:
parent
1e2e17784a
commit
cc44deee1a
|
@ -25,7 +25,7 @@ public final class Msg {
|
|||
|
||||
/**
|
||||
* IMPORTANT: Please update the following comment after you add a new code
|
||||
* Last code value: 2034
|
||||
* Last code value: 2036
|
||||
*/
|
||||
|
||||
private Msg() {}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package ca.uhn.fhir.util;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* This is used to allow lazy parameter initialization for SLF4j - Hopefully
|
||||
* a future version will allow lambda params
|
||||
*/
|
||||
public class MessageSupplier {
|
||||
private Supplier<?> supplier;
|
||||
|
||||
public MessageSupplier(Supplier<?> supplier) {
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return supplier.get().toString();
|
||||
}
|
||||
|
||||
public static MessageSupplier msg(Supplier<?> supplier) {
|
||||
return new MessageSupplier(supplier);
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.util;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.CharArrayWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.Normalizer;
|
||||
|
@ -105,4 +106,13 @@ public class StringUtil {
|
|||
return theString.substring(0, theString.offsetByCodePoints(0, theCodePointCount));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static String prependLineNumbers(@Nonnull String theInput) {
|
||||
StringBuilder schemaOutput = new StringBuilder();
|
||||
int index = 0;
|
||||
for (String next : theInput.split("\\n")) {
|
||||
schemaOutput.append(index++).append(": ").append(next.replace("\r", "")).append("\n");
|
||||
}
|
||||
return schemaOutput.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package ca.uhn.fhir.util;
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.Appender;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static ca.uhn.fhir.util.MessageSupplier.msg;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class MessageSupplierTest {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(MessageSupplierTest.class);
|
||||
private Appender myMockAppender;
|
||||
private ch.qos.logback.classic.Logger myLoggerRoot;
|
||||
|
||||
@AfterEach
|
||||
public void after() {
|
||||
myLoggerRoot.detachAppender(myMockAppender);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
|
||||
/*
|
||||
* This is a bit funky, but it's useful for verifying that the headers actually get logged
|
||||
*/
|
||||
myMockAppender = mock(Appender.class);
|
||||
when(myMockAppender.getName()).thenReturn("MOCK");
|
||||
|
||||
Logger logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||
|
||||
myLoggerRoot = (ch.qos.logback.classic.Logger) logger;
|
||||
myLoggerRoot.addAppender(myMockAppender);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLog() {
|
||||
|
||||
ourLog.info("Hello: {}", msg(() -> "Goodbye"));
|
||||
|
||||
verify(myMockAppender, times(1)).doAppend(argThat((ArgumentMatcher<ILoggingEvent>) argument -> {
|
||||
String formattedMessage = argument.getFormattedMessage();
|
||||
System.out.flush();
|
||||
System.out.println("** Got Message: " + formattedMessage);
|
||||
System.out.flush();
|
||||
return formattedMessage.equals("Hello: Goodbye");
|
||||
}));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -64,4 +64,9 @@ public class StringUtilTest {
|
|||
assertEquals("a/a", StringUtil.chompCharacter("a/a////", '/'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrependLineNumbers() {
|
||||
assertEquals("0: A\n1: B\n", StringUtil.prependLineNumbers("A\nB"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: add
|
||||
issue: 3348
|
||||
title: "The HAPI FHIR server GraphQL endpoints now support GraphQL introspection, making them
|
||||
much easier to use with GraphQL-capable IDEs."
|
|
@ -15,24 +15,6 @@
|
|||
<name>HAPI FHIR JPA Server</name>
|
||||
|
||||
<dependencies>
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.jaxrs</groupId>
|
||||
<artifactId>jackson-jaxrs-json-provider</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-hibernate4</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.5</version>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.woodstox</groupId>
|
||||
|
@ -174,6 +156,12 @@
|
|||
<artifactId>javassist</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- GraphQL -->
|
||||
<dependency>
|
||||
<groupId>com.graphql-java</groupId>
|
||||
<artifactId>graphql-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SQL Builder -->
|
||||
<dependency>
|
||||
<groupId>com.healthmarketscience.sqlbuilder</groupId>
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.config.dstu3;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.api.IDaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.config.GeneratedDaoAndResourceProviderConfigDstu3;
|
||||
import ca.uhn.fhir.jpa.config.JpaConfig;
|
||||
|
@ -9,6 +10,7 @@ import ca.uhn.fhir.jpa.config.SharedConfigDstu3Plus;
|
|||
import ca.uhn.fhir.jpa.dao.ITransactionProcessorVersionAdapter;
|
||||
import ca.uhn.fhir.jpa.dao.dstu3.TransactionProcessorVersionAdapterDstu3;
|
||||
import ca.uhn.fhir.jpa.graphql.GraphQLProvider;
|
||||
import ca.uhn.fhir.jpa.graphql.GraphQLProviderWithIntrospection;
|
||||
import ca.uhn.fhir.jpa.term.TermLoaderSvcImpl;
|
||||
import ca.uhn.fhir.jpa.term.TermReadSvcDstu3;
|
||||
import ca.uhn.fhir.jpa.term.TermVersionAdapterSvcDstu3;
|
||||
|
@ -17,6 +19,7 @@ import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
|
|||
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvcDstu3;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
|
||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Meta;
|
||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||
|
@ -62,8 +65,8 @@ public class JpaDstu3Config {
|
|||
|
||||
@Bean(name = JpaConfig.GRAPHQL_PROVIDER_NAME)
|
||||
@Lazy
|
||||
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport) {
|
||||
return new GraphQLProvider(theFhirContext, theValidationSupport, theGraphqlStorageServices);
|
||||
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport, ISearchParamRegistry theSearchParamRegistry, IDaoRegistry theDaoRegistry) {
|
||||
return new GraphQLProviderWithIntrospection(theFhirContext, theValidationSupport, theGraphqlStorageServices, theSearchParamRegistry, theDaoRegistry);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.config.r4;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.api.IDaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.config.GeneratedDaoAndResourceProviderConfigR4;
|
||||
import ca.uhn.fhir.jpa.config.JpaConfig;
|
||||
|
@ -9,6 +10,7 @@ import ca.uhn.fhir.jpa.config.SharedConfigDstu3Plus;
|
|||
import ca.uhn.fhir.jpa.dao.ITransactionProcessorVersionAdapter;
|
||||
import ca.uhn.fhir.jpa.dao.r4.TransactionProcessorVersionAdapterR4;
|
||||
import ca.uhn.fhir.jpa.graphql.GraphQLProvider;
|
||||
import ca.uhn.fhir.jpa.graphql.GraphQLProviderWithIntrospection;
|
||||
import ca.uhn.fhir.jpa.term.TermLoaderSvcImpl;
|
||||
import ca.uhn.fhir.jpa.term.TermReadSvcR4;
|
||||
import ca.uhn.fhir.jpa.term.TermVersionAdapterSvcR4;
|
||||
|
@ -17,6 +19,7 @@ import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
|
|||
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvcR4;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
|
||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Meta;
|
||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||
|
@ -26,6 +29,26 @@ import org.springframework.context.annotation.Import;
|
|||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@Import({
|
||||
|
@ -48,8 +71,8 @@ public class JpaR4Config {
|
|||
|
||||
@Bean(name = JpaConfig.GRAPHQL_PROVIDER_NAME)
|
||||
@Lazy
|
||||
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport) {
|
||||
return new GraphQLProvider(theFhirContext, theValidationSupport, theGraphqlStorageServices);
|
||||
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport, ISearchParamRegistry theSearchParamRegistry, IDaoRegistry theDaoRegistry) {
|
||||
return new GraphQLProviderWithIntrospection(theFhirContext, theValidationSupport, theGraphqlStorageServices, theSearchParamRegistry, theDaoRegistry);
|
||||
}
|
||||
|
||||
@Bean(name = "mySystemDaoR4")
|
||||
|
@ -77,23 +100,3 @@ public class JpaR4Config {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.config.r5;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.api.IDaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.config.GeneratedDaoAndResourceProviderConfigR5;
|
||||
import ca.uhn.fhir.jpa.config.JpaConfig;
|
||||
|
@ -9,6 +10,7 @@ import ca.uhn.fhir.jpa.config.SharedConfigDstu3Plus;
|
|||
import ca.uhn.fhir.jpa.dao.ITransactionProcessorVersionAdapter;
|
||||
import ca.uhn.fhir.jpa.dao.r5.TransactionProcessorVersionAdapterR5;
|
||||
import ca.uhn.fhir.jpa.graphql.GraphQLProvider;
|
||||
import ca.uhn.fhir.jpa.graphql.GraphQLProviderWithIntrospection;
|
||||
import ca.uhn.fhir.jpa.term.TermLoaderSvcImpl;
|
||||
import ca.uhn.fhir.jpa.term.TermReadSvcR5;
|
||||
import ca.uhn.fhir.jpa.term.TermVersionAdapterSvcR5;
|
||||
|
@ -17,6 +19,7 @@ import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
|
|||
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvcR5;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
|
||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.Meta;
|
||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||
|
@ -68,8 +71,8 @@ public class JpaR5Config {
|
|||
|
||||
@Bean(name = JpaConfig.GRAPHQL_PROVIDER_NAME)
|
||||
@Lazy
|
||||
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport) {
|
||||
return new GraphQLProvider(theFhirContext, theValidationSupport, theGraphqlStorageServices);
|
||||
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport, ISearchParamRegistry theSearchParamRegistry, IDaoRegistry theDaoRegistry) {
|
||||
return new GraphQLProviderWithIntrospection(theFhirContext, theValidationSupport, theGraphqlStorageServices, theSearchParamRegistry, theDaoRegistry);
|
||||
}
|
||||
|
||||
@Bean(name = "mySystemDaoR5")
|
||||
|
|
|
@ -161,6 +161,9 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
|
|||
@Nullable
|
||||
@Override
|
||||
public <T extends IBaseResource> List<T> fetchAllStructureDefinitions() {
|
||||
if (!myDaoRegistry.isResourceTypeSupported("StructureDefinition")) {
|
||||
return null;
|
||||
}
|
||||
IBundleProvider search = myDaoRegistry.getResourceDao("StructureDefinition").search(new SearchParameterMap().setLoadSynchronousUpTo(1000));
|
||||
return (List<T>) search.getResources(0, 1000);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,269 @@
|
|||
package ca.uhn.fhir.jpa.graphql;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.api.IDaoRegistry;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.util.StringUtil;
|
||||
import ca.uhn.fhir.util.VersionUtil;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import graphql.ExecutionResult;
|
||||
import graphql.GraphQL;
|
||||
import graphql.scalar.GraphqlStringCoercing;
|
||||
import graphql.schema.GraphQLScalarType;
|
||||
import graphql.schema.GraphQLSchema;
|
||||
import graphql.schema.idl.RuntimeWiring;
|
||||
import graphql.schema.idl.SchemaGenerator;
|
||||
import graphql.schema.idl.SchemaParser;
|
||||
import graphql.schema.idl.TypeDefinitionRegistry;
|
||||
import org.apache.commons.io.output.StringBuilderWriter;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.common.hapi.validation.validator.VersionSpecificWorkerContextWrapper;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r5.model.Enumerations;
|
||||
import org.hl7.fhir.r5.model.SearchParameter;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.utils.GraphQLSchemaGenerator;
|
||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.util.MessageSupplier.msg;
|
||||
|
||||
public class GraphQLProviderWithIntrospection extends GraphQLProvider {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(GraphQLProviderWithIntrospection.class);
|
||||
private final GraphQLSchemaGenerator myGenerator;
|
||||
private final ISearchParamRegistry mySearchParamRegistry;
|
||||
private final VersionSpecificWorkerContextWrapper myContext;
|
||||
private final IDaoRegistry myDaoRegistry;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public GraphQLProviderWithIntrospection(FhirContext theFhirContext, IValidationSupport theValidationSupport, IGraphQLStorageServices theIGraphQLStorageServices, ISearchParamRegistry theSearchParamRegistry, IDaoRegistry theDaoRegistry) {
|
||||
super(theFhirContext, theValidationSupport, theIGraphQLStorageServices);
|
||||
|
||||
mySearchParamRegistry = theSearchParamRegistry;
|
||||
myDaoRegistry = theDaoRegistry;
|
||||
|
||||
myContext = VersionSpecificWorkerContextWrapper.newVersionSpecificWorkerContextWrapper(theValidationSupport);
|
||||
myGenerator = new GraphQLSchemaGenerator(myContext, VersionUtil.getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String processGraphQlGetRequest(ServletRequestDetails theRequestDetails, IIdType theId, String theQueryUrl) {
|
||||
return super.processGraphQlGetRequest(theRequestDetails, theId, theQueryUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String processGraphQlPostRequest(ServletRequestDetails theServletRequestDetails, RequestDetails theRequestDetails, IIdType theId, String theQueryBody) {
|
||||
if (theQueryBody.contains("__schema")) {
|
||||
EnumSet<GraphQLSchemaGenerator.FHIROperationType> operations;
|
||||
if (theId != null) {
|
||||
throw new InvalidRequestException(Msg.code(2035) + "GraphQL introspection not supported at instance level. Please try at server- or instance- level.");
|
||||
}
|
||||
|
||||
operations = EnumSet.of(GraphQLSchemaGenerator.FHIROperationType.READ, GraphQLSchemaGenerator.FHIROperationType.SEARCH);
|
||||
|
||||
Collection<String> resourceTypes;
|
||||
if (theRequestDetails.getResourceName() != null) {
|
||||
resourceTypes = Collections.singleton(theRequestDetails.getResourceName());
|
||||
} else {
|
||||
resourceTypes = new HashSet<>();
|
||||
for (String next : myContext.getResourceNames()) {
|
||||
if (myDaoRegistry.isResourceTypeSupported(next)) {
|
||||
resourceTypes.add(next);
|
||||
}
|
||||
}
|
||||
resourceTypes = resourceTypes
|
||||
.stream()
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return generateSchema(theQueryBody, resourceTypes, operations);
|
||||
} else {
|
||||
return super.processGraphQlPostRequest(theServletRequestDetails, theRequestDetails, theId, theQueryBody);
|
||||
}
|
||||
}
|
||||
|
||||
private String generateSchema(String theQueryBody, Collection<String> theResourceTypes, EnumSet<GraphQLSchemaGenerator.FHIROperationType> theOperations) {
|
||||
|
||||
final StringBuilder schemaBuilder = new StringBuilder();
|
||||
try (Writer writer = new StringBuilderWriter(schemaBuilder)) {
|
||||
// Generate FHIR base types schemas
|
||||
myGenerator.generateTypes(writer, theOperations);
|
||||
|
||||
// Fix up a few things that are missing from the generated schema
|
||||
writer
|
||||
.append("\ntype Resource {")
|
||||
.append("\n id: [token]" + "\n}")
|
||||
.append("\n");
|
||||
writer
|
||||
.append("\ninput ResourceInput {")
|
||||
.append("\n id: [token]" + "\n}")
|
||||
.append("\n");
|
||||
|
||||
// Generate schemas for the resource types
|
||||
for (String nextResourceType : theResourceTypes) {
|
||||
StructureDefinition sd = fetchStructureDefinition(nextResourceType);
|
||||
List<SearchParameter> parameters = toR5SearchParams(mySearchParamRegistry.getActiveSearchParams(nextResourceType).values());
|
||||
myGenerator.generateResource(writer, sd, parameters, theOperations);
|
||||
}
|
||||
|
||||
// Generate queries
|
||||
writer.append("\ntype Query {");
|
||||
for (String nextResourceType : theResourceTypes) {
|
||||
if (theOperations.contains(GraphQLSchemaGenerator.FHIROperationType.READ)) {
|
||||
writer
|
||||
.append("\n ")
|
||||
.append(nextResourceType)
|
||||
.append("(id: String): ")
|
||||
.append(nextResourceType)
|
||||
.append("\n");
|
||||
}
|
||||
if (theOperations.contains(GraphQLSchemaGenerator.FHIROperationType.SEARCH)) {
|
||||
List<SearchParameter> parameters = toR5SearchParams(mySearchParamRegistry.getActiveSearchParams(nextResourceType).values());
|
||||
myGenerator.generateListAccessQuery(writer, parameters, nextResourceType);
|
||||
myGenerator.generateConnectionAccessQuery(writer, parameters, nextResourceType);
|
||||
}
|
||||
}
|
||||
writer.append("\n}");
|
||||
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
throw new InternalErrorException(Msg.code(2036) + e.getMessage(), e);
|
||||
}
|
||||
|
||||
String schema = schemaBuilder.toString().replace("\r", "");
|
||||
|
||||
// Set these to INFO if you're testing, then set back before committing
|
||||
ourLog.debug("Schema generated: {} chars", schema.length());
|
||||
ourLog.debug("Schema generated: {}", msg(() -> StringUtil.prependLineNumbers(schema)));
|
||||
|
||||
SchemaParser schemaParser = new SchemaParser();
|
||||
TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema);
|
||||
|
||||
SchemaGenerator schemaGenerator = new SchemaGenerator();
|
||||
RuntimeWiring.Builder runtimeWiringBuilder = RuntimeWiring.newRuntimeWiring();
|
||||
for (String next : typeDefinitionRegistry.scalars().keySet()) {
|
||||
if (Character.isUpperCase(next.charAt(0))) {
|
||||
// Skip GraphQL built-in types
|
||||
continue;
|
||||
}
|
||||
runtimeWiringBuilder.scalar(new GraphQLScalarType.Builder().name(next).coercing(new GraphqlStringCoercing()).build());
|
||||
}
|
||||
|
||||
RuntimeWiring runtimeWiring = runtimeWiringBuilder.build();
|
||||
GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring);
|
||||
|
||||
GraphQL build = GraphQL.newGraphQL(graphQLSchema).build();
|
||||
ExecutionResult executionResult = build.execute(theQueryBody);
|
||||
|
||||
Map<String, Object> data = executionResult.toSpecification();
|
||||
Gson gson = new GsonBuilder().create();
|
||||
return gson.toJson(data);
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private List<SearchParameter> toR5SearchParams(Collection<RuntimeSearchParam> searchParams) {
|
||||
List<SearchParameter> parameters = new ArrayList<>();
|
||||
for (RuntimeSearchParam next : searchParams) {
|
||||
SearchParameter sp = toR5SearchParam(next);
|
||||
if (sp != null) {
|
||||
parameters.add(sp);
|
||||
}
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SearchParameter toR5SearchParam(RuntimeSearchParam next) {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setUrl(next.getUri());
|
||||
sp.setCode(next.getName());
|
||||
sp.setName(next.getName());
|
||||
|
||||
switch (next.getParamType()) {
|
||||
case NUMBER:
|
||||
sp.setType(Enumerations.SearchParamType.NUMBER);
|
||||
break;
|
||||
case DATE:
|
||||
sp.setType(Enumerations.SearchParamType.DATE);
|
||||
break;
|
||||
case STRING:
|
||||
sp.setType(Enumerations.SearchParamType.STRING);
|
||||
break;
|
||||
case TOKEN:
|
||||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
break;
|
||||
case REFERENCE:
|
||||
sp.setType(Enumerations.SearchParamType.REFERENCE);
|
||||
break;
|
||||
case COMPOSITE:
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
break;
|
||||
case QUANTITY:
|
||||
sp.setType(Enumerations.SearchParamType.QUANTITY);
|
||||
break;
|
||||
case URI:
|
||||
sp.setType(Enumerations.SearchParamType.URI);
|
||||
break;
|
||||
case HAS:
|
||||
case SPECIAL:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return sp;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private StructureDefinition fetchStructureDefinition(String resourceName) {
|
||||
StructureDefinition retVal = myContext.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + resourceName);
|
||||
Validate.notNull(retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
|
@ -722,16 +722,6 @@ public abstract class BaseJpaTest extends BaseTest {
|
|||
doRandomizeLocaleAndTimezone();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClassShutdownDerby() {
|
||||
// DriverManager.getConnection("jdbc:derby:;shutdown=true");
|
||||
// try {
|
||||
// DriverManager.getConnection("jdbc:derby:memory:myUnitTestDB;drop=true");
|
||||
// } catch (SQLNonTransientConnectionException e) {
|
||||
// // expected.. for some reason....
|
||||
// }
|
||||
}
|
||||
|
||||
public static String loadClasspath(String resource) throws IOException {
|
||||
return new String(loadClasspathBytes(resource), Constants.CHARSET_UTF8);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
|||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
|
@ -105,6 +106,10 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
|||
.collect(Collectors.toList());
|
||||
assertThat(paths.toString(), paths, contains("Observation.subject", "Observation.subject.where(resolve() is Patient)"));
|
||||
});
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
assertEquals(1, myObservationDao.search(SearchParameterMap.newSynchronous("patient", new ReferenceParam("Patient/A"))).sizeOrThrowNpe());
|
||||
myCaptureQueriesListener.logSelectQueries();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -5,12 +5,9 @@ import ca.uhn.fhir.jpa.graphql.GraphQLProvider;
|
|||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -19,9 +16,6 @@ import org.apache.http.client.methods.HttpGet;
|
|||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseReference;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -35,6 +29,7 @@ import org.junit.jupiter.api.AfterAll;
|
|||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
|
@ -47,15 +42,19 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class JpaGraphQLR4ProviderTest {
|
||||
public class GraphQLR4ProviderTest {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JpaGraphQLR4ProviderTest.class);
|
||||
public static final String DATA_PREFIX = "{\"data\": ";
|
||||
public static final String DATA_SUFFIX = "}";
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GraphQLR4ProviderTest.class);
|
||||
private static final FhirContext ourCtx = FhirContext.forR4Cached();
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static CloseableHttpClient ourClient;
|
||||
private MyStorageServices myGraphQLStorageServices = new MyStorageServices();
|
||||
|
||||
@RegisterExtension
|
||||
private RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(ourCtx)
|
||||
.registerProvider(new DummyPatientResourceProvider())
|
||||
.registerProvider(new GraphQLProvider(myGraphQLStorageServices));
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
|
@ -65,9 +64,8 @@ public class JpaGraphQLR4ProviderTest {
|
|||
@Test
|
||||
public void testGraphInstance() throws Exception {
|
||||
String query = "{name{family,given}}";
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
@ -81,9 +79,6 @@ public class JpaGraphQLR4ProviderTest {
|
|||
" }]\n" +
|
||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -91,9 +86,8 @@ public class JpaGraphQLR4ProviderTest {
|
|||
@Test
|
||||
public void testGraphInstanceWithFhirpath() throws Exception {
|
||||
String query = "{name(fhirpath:\"family.exists()\"){text,given,family}}";
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
@ -105,9 +99,6 @@ public class JpaGraphQLR4ProviderTest {
|
|||
" }]\n" +
|
||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -115,9 +106,8 @@ public class JpaGraphQLR4ProviderTest {
|
|||
@Test
|
||||
public void testGraphSystemInstance() throws Exception {
|
||||
String query = "{Patient(id:123){id,name{given,family}}}";
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
@ -133,9 +123,6 @@ public class JpaGraphQLR4ProviderTest {
|
|||
" }\n" +
|
||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -143,9 +130,9 @@ public class JpaGraphQLR4ProviderTest {
|
|||
@Test
|
||||
public void testGraphSystemList() throws Exception {
|
||||
String query = "{PatientList(name:\"pet\"){name{family,given}}}";
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
@ -166,8 +153,6 @@ public class JpaGraphQLR4ProviderTest {
|
|||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -175,9 +160,8 @@ public class JpaGraphQLR4ProviderTest {
|
|||
@Test
|
||||
public void testGraphSystemArrayArgumentList() throws Exception {
|
||||
String query = "{PatientList(id:[\"hapi-123\",\"hapi-124\"]){id,name{family}}}";
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
@ -196,41 +180,21 @@ public class JpaGraphQLR4ProviderTest {
|
|||
" }]\n" +
|
||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
JettyUtil.closeServer(ourServer);
|
||||
ourClient.close();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
ourServer = new Server(0);
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||
|
||||
servlet.registerProvider(new DummyPatientResourceProvider());
|
||||
MyStorageServices storageServices = new MyStorageServices();
|
||||
servlet.registerProvider(new GraphQLProvider(storageServices));
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
JettyUtil.startServer(ourServer);
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
|
@ -14,8 +14,8 @@ import org.slf4j.LoggerFactory;
|
|||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static ca.uhn.fhir.jpa.provider.JpaGraphQLR4ProviderTest.DATA_PREFIX;
|
||||
import static ca.uhn.fhir.jpa.provider.JpaGraphQLR4ProviderTest.DATA_SUFFIX;
|
||||
import static ca.uhn.fhir.jpa.provider.GraphQLR4ProviderTest.DATA_PREFIX;
|
||||
import static ca.uhn.fhir.jpa.provider.GraphQLR4ProviderTest.DATA_SUFFIX;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class GraphQLProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static ca.uhn.fhir.jpa.provider.JpaGraphQLR4ProviderTest.DATA_PREFIX;
|
||||
import static ca.uhn.fhir.jpa.provider.JpaGraphQLR4ProviderTest.DATA_SUFFIX;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class GraphQLProviderR4Test extends BaseResourceProviderR4Test {
|
||||
private Logger ourLog = LoggerFactory.getLogger(GraphQLProviderR4Test.class);
|
||||
private IIdType myPatientId0;
|
||||
|
||||
@Test
|
||||
public void testInstanceSimpleRead() throws IOException {
|
||||
initTestPatients();
|
||||
|
||||
String query = "{name{family,given}}";
|
||||
HttpGet httpGet = new HttpGet(ourServerBase + "/Patient/" + myPatientId0.getIdPart() + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
|
||||
try (CloseableHttpResponse response = ourHttpClient.execute(httpGet)) {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(resp);
|
||||
assertEquals(TestUtil.stripWhitespace(DATA_PREFIX + "{\n" +
|
||||
" \"name\":[{\n" +
|
||||
" \"family\":\"FAM\",\n" +
|
||||
" \"given\":[\"GIVEN1\",\"GIVEN2\"]\n" +
|
||||
" },{\n" +
|
||||
" \"given\":[\"GivenOnly1\",\"GivenOnly2\"]\n" +
|
||||
" }]\n" +
|
||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(resp));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSystemSimpleSearch() throws IOException {
|
||||
initTestPatients();
|
||||
|
||||
String query = "{PatientList(given:\"given\"){name{family,given}}}";
|
||||
HttpGet httpGet = new HttpGet(ourServerBase + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
|
||||
try (CloseableHttpResponse response = ourHttpClient.execute(httpGet)) {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(resp);
|
||||
assertEquals(TestUtil.stripWhitespace(DATA_PREFIX + "{\n" +
|
||||
" \"PatientList\":[{\n" +
|
||||
" \"name\":[{\n" +
|
||||
" \"family\":\"FAM\",\n" +
|
||||
" \"given\":[\"GIVEN1\",\"GIVEN2\"]\n" +
|
||||
" },{\n" +
|
||||
" \"given\":[\"GivenOnly1\",\"GivenOnly2\"]\n" +
|
||||
" }]\n" +
|
||||
" },{\n" +
|
||||
" \"name\":[{\n" +
|
||||
" \"given\":[\"GivenOnlyB1\",\"GivenOnlyB2\"]\n" +
|
||||
" }]\n" +
|
||||
" }]\n" +
|
||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(resp));
|
||||
}
|
||||
}
|
||||
|
||||
private void initTestPatients() {
|
||||
Patient p = new Patient();
|
||||
p.addName()
|
||||
.setFamily("FAM")
|
||||
.addGiven("GIVEN1")
|
||||
.addGiven("GIVEN2");
|
||||
p.addName()
|
||||
.addGiven("GivenOnly1")
|
||||
.addGiven("GivenOnly2");
|
||||
myPatientId0 = myClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
p = new Patient();
|
||||
p.addName()
|
||||
.addGiven("GivenOnlyB1")
|
||||
.addGiven("GivenOnlyB2");
|
||||
myClient.create().resource(p).execute();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import ca.uhn.fhir.util.FileUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static ca.uhn.fhir.jpa.provider.GraphQLR4ProviderTest.DATA_PREFIX;
|
||||
import static ca.uhn.fhir.jpa.provider.GraphQLR4ProviderTest.DATA_SUFFIX;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@TestMethodOrder(MethodOrderer.MethodName.class)
|
||||
public class GraphQLR4Test extends BaseResourceProviderR4Test {
|
||||
public static final String INTROSPECTION_QUERY = "{\"query\":\"\\n query IntrospectionQuery {\\n __schema {\\n queryType { name }\\n mutationType { name }\\n subscriptionType { name }\\n types {\\n ...FullType\\n }\\n directives {\\n name\\n description\\n locations\\n args {\\n ...InputValue\\n }\\n }\\n }\\n }\\n\\n fragment FullType on __Type {\\n kind\\n name\\n description\\n fields(includeDeprecated: true) {\\n name\\n description\\n args {\\n ...InputValue\\n }\\n type {\\n ...TypeRef\\n }\\n isDeprecated\\n deprecationReason\\n }\\n inputFields {\\n ...InputValue\\n }\\n interfaces {\\n ...TypeRef\\n }\\n enumValues(includeDeprecated: true) {\\n name\\n description\\n isDeprecated\\n deprecationReason\\n }\\n possibleTypes {\\n ...TypeRef\\n }\\n }\\n\\n fragment InputValue on __InputValue {\\n name\\n description\\n type { ...TypeRef }\\n defaultValue\\n }\\n\\n fragment TypeRef on __Type {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n ofType {\\n kind\\n name\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n \",\"operationName\":\"IntrospectionQuery\"}";
|
||||
private Logger ourLog = LoggerFactory.getLogger(GraphQLR4Test.class);
|
||||
private IIdType myPatientId0;
|
||||
|
||||
@Test
|
||||
public void testInstance_Read_Patient() throws IOException {
|
||||
initTestPatients();
|
||||
|
||||
String query = "{name{family,given}}";
|
||||
HttpGet httpGet = new HttpGet(ourServerBase + "/Patient/" + myPatientId0.getIdPart() + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
|
||||
try (CloseableHttpResponse response = ourHttpClient.execute(httpGet)) {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(resp);
|
||||
assertEquals(TestUtil.stripWhitespace(DATA_PREFIX + "{\n" +
|
||||
" \"name\":[{\n" +
|
||||
" \"family\":\"FAM\",\n" +
|
||||
" \"given\":[\"GIVEN1\",\"GIVEN2\"]\n" +
|
||||
" },{\n" +
|
||||
" \"given\":[\"GivenOnly1\",\"GivenOnly2\"]\n" +
|
||||
" }]\n" +
|
||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(resp));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testType_Introspect_Patient() throws IOException {
|
||||
initTestPatients();
|
||||
|
||||
String uri = ourServerBase + "/Patient/$graphql";
|
||||
HttpPost httpGet = new HttpPost(uri);
|
||||
httpGet.setEntity(new StringEntity(INTROSPECTION_QUERY, ContentType.APPLICATION_JSON));
|
||||
|
||||
// Repeat a couple of times to make sure it doesn't fail after the first one. At one point
|
||||
// the generator polluted the structure userdata and failed the second time
|
||||
for (int i = 0; i < 3; i++) {
|
||||
try (CloseableHttpResponse response = ourHttpClient.execute(httpGet)) {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(resp);
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
assertThat(resp, containsString("{\"kind\":\"OBJECT\",\"name\":\"Patient\","));
|
||||
assertThat(resp, not(containsString("{\"kind\":\"OBJECT\",\"name\":\"Observation\",")));
|
||||
assertThat(resp, not(containsString("\"name\":\"Observation\",\"args\":[{\"name\":\"id\"")));
|
||||
assertThat(resp, not(containsString("\"name\":\"ObservationList\",\"args\":[{\"name\":\"_filter\"")));
|
||||
assertThat(resp, not(containsString("\"name\":\"ObservationConnection\",\"fields\":[{\"name\":\"count\"")));
|
||||
assertThat(resp, containsString("\"name\":\"Patient\",\"args\":[{\"name\":\"id\""));
|
||||
assertThat(resp, containsString("\"name\":\"PatientList\",\"args\":[{\"name\":\"_filter\""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testType_Introspect_Observation() throws IOException {
|
||||
initTestPatients();
|
||||
|
||||
String uri = ourServerBase + "/Observation/$graphql";
|
||||
HttpPost httpGet = new HttpPost(uri);
|
||||
httpGet.setEntity(new StringEntity(INTROSPECTION_QUERY, ContentType.APPLICATION_JSON));
|
||||
|
||||
// Repeat a couple of times to make sure it doesn't fail after the first one. At one point
|
||||
// the generator polluted the structure userdata and failed the second time
|
||||
for (int i = 0; i < 3; i++) {
|
||||
try (CloseableHttpResponse response = ourHttpClient.execute(httpGet)) {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(resp);
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
assertThat(resp, not(containsString("{\"kind\":\"OBJECT\",\"name\":\"Patient\",")));
|
||||
assertThat(resp, containsString("{\"kind\":\"OBJECT\",\"name\":\"Observation\","));
|
||||
assertThat(resp, not(containsString("{\"kind\":\"OBJECT\",\"name\":\"Query\",\"fields\":[{\"name\":\"PatientList\"")));
|
||||
assertThat(resp, containsString("\"name\":\"Observation\",\"args\":[{\"name\":\"id\""));
|
||||
assertThat(resp, containsString("\"name\":\"ObservationList\",\"args\":[{\"name\":\"_filter\""));
|
||||
assertThat(resp, containsString("\"name\":\"ObservationConnection\",\"fields\":[{\"name\":\"count\""));
|
||||
assertThat(resp, not(containsString("\"name\":\"Patient\",\"args\":[{\"name\":\"id\"")));
|
||||
assertThat(resp, not(containsString("\"name\":\"PatientList\",\"args\":[{\"name\":\"_filter\"")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoot_Introspect() throws IOException {
|
||||
initTestPatients();
|
||||
|
||||
String uri = ourServerBase + "/$graphql";
|
||||
HttpPost httpGet = new HttpPost(uri);
|
||||
httpGet.setEntity(new StringEntity(INTROSPECTION_QUERY, ContentType.APPLICATION_JSON));
|
||||
|
||||
// Repeat a couple of times to make sure it doesn't fail after the first one. At one point
|
||||
// the generator polluted the structure userdata and failed the second time
|
||||
for (int i = 0; i < 3; i++) {
|
||||
try (CloseableHttpResponse response = ourHttpClient.execute(httpGet)) {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info("Response has size: {}", FileUtil.formatFileSize(resp.length()));
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
assertThat(resp, containsString("{\"kind\":\"OBJECT\",\"name\":\"Patient\","));
|
||||
assertThat(resp, containsString("{\"kind\":\"OBJECT\",\"name\":\"Observation\","));
|
||||
assertThat(resp, containsString("\"name\":\"Observation\",\"args\":[{\"name\":\"id\""));
|
||||
assertThat(resp, containsString("\"name\":\"ObservationList\",\"args\":[{\"name\":\"_filter\""));
|
||||
assertThat(resp, containsString("\"name\":\"ObservationConnection\",\"fields\":[{\"name\":\"count\""));
|
||||
assertThat(resp, containsString("\"name\":\"Patient\",\"args\":[{\"name\":\"id\""));
|
||||
assertThat(resp, containsString("\"name\":\"PatientList\",\"args\":[{\"name\":\"_filter\""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoot_Read_Patient() throws IOException {
|
||||
initTestPatients();
|
||||
|
||||
String query = "{Patient(id:\"" + myPatientId0.getIdPart() + "\"){name{family,given}}}";
|
||||
HttpGet httpGet = new HttpGet(ourServerBase + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
|
||||
try (CloseableHttpResponse response = ourHttpClient.execute(httpGet)) {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(resp);
|
||||
assertEquals(TestUtil.stripWhitespace(DATA_PREFIX +
|
||||
"{\n" +
|
||||
"\"Patient\":{\n" +
|
||||
"\"name\":[{\n" +
|
||||
"\"family\":\"FAM\",\n" +
|
||||
"\"given\":[\"GIVEN1\",\"GIVEN2\"]\n" +
|
||||
"},{\n" +
|
||||
"\"given\":[\"GivenOnly1\",\"GivenOnly2\"]\n" +
|
||||
"}]\n" +
|
||||
"}\n" +
|
||||
"}" +
|
||||
DATA_SUFFIX), TestUtil.stripWhitespace(resp));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testRoot_Search_Patient() throws IOException {
|
||||
initTestPatients();
|
||||
|
||||
String query = "{PatientList(given:\"given\"){name{family,given}}}";
|
||||
HttpGet httpGet = new HttpGet(ourServerBase + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
|
||||
try (CloseableHttpResponse response = ourHttpClient.execute(httpGet)) {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(resp);
|
||||
assertEquals(TestUtil.stripWhitespace(DATA_PREFIX + "{\n" +
|
||||
" \"PatientList\":[{\n" +
|
||||
" \"name\":[{\n" +
|
||||
" \"family\":\"FAM\",\n" +
|
||||
" \"given\":[\"GIVEN1\",\"GIVEN2\"]\n" +
|
||||
" },{\n" +
|
||||
" \"given\":[\"GivenOnly1\",\"GivenOnly2\"]\n" +
|
||||
" }]\n" +
|
||||
" },{\n" +
|
||||
" \"name\":[{\n" +
|
||||
" \"given\":[\"GivenOnlyB1\",\"GivenOnlyB2\"]\n" +
|
||||
" }]\n" +
|
||||
" }]\n" +
|
||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(resp));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoot_Search_Observation() throws IOException {
|
||||
initTestPatients();
|
||||
|
||||
String query = "{ObservationList(date: \"2022\") {id}}";
|
||||
HttpGet httpGet = new HttpGet(ourServerBase + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||
|
||||
myCaptureQueriesListener.clear();
|
||||
try (CloseableHttpResponse response = ourHttpClient.execute(httpGet)) {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(resp);
|
||||
}
|
||||
myCaptureQueriesListener.logSelectQueries();
|
||||
}
|
||||
|
||||
private void initTestPatients() {
|
||||
Patient p = new Patient();
|
||||
p.addName()
|
||||
.setFamily("FAM")
|
||||
.addGiven("GIVEN1")
|
||||
.addGiven("GIVEN2");
|
||||
p.addName()
|
||||
.addGiven("GivenOnly1")
|
||||
.addGiven("GivenOnly2");
|
||||
myPatientId0 = myClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
p = new Patient();
|
||||
p.addName()
|
||||
.addGiven("GivenOnlyB1")
|
||||
.addGiven("GivenOnlyB2");
|
||||
myClient.create().resource(p).execute();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jpaserver-base</artifactId>
|
||||
|
@ -102,6 +103,12 @@
|
|||
</dependency>
|
||||
|
||||
<!-- TEST DEPS -->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
|
|
|
@ -35,6 +35,7 @@ import ca.uhn.fhir.rest.server.interceptor.FhirPathFilterInterceptor;
|
|||
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory;
|
||||
import ca.uhn.fhirtest.config.SqlCaptureInterceptor;
|
||||
import ca.uhn.fhirtest.config.TestDstu2Config;
|
||||
import ca.uhn.fhirtest.config.TestDstu3Config;
|
||||
import ca.uhn.fhirtest.config.TestR4Config;
|
||||
|
@ -282,6 +283,8 @@ public class TestRestfulServer extends RestfulServer {
|
|||
loggingInterceptor.setMessageFormat("${operationType} Content-Type: ${requestHeader.content-type} - Accept: ${responseEncodingNoDefault} \"${requestHeader.accept}\" - Agent: ${requestHeader.user-agent}");
|
||||
registerInterceptor(loggingInterceptor);
|
||||
|
||||
// SQL Capturing
|
||||
registerInterceptor(myAppCtx.getBean(SqlCaptureInterceptor.class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,11 +5,11 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
|||
import ca.uhn.fhir.jpa.config.HapiJpaConfig;
|
||||
import ca.uhn.fhir.jpa.config.JpaDstu2Config;
|
||||
import ca.uhn.fhir.jpa.config.util.HapiEntityManagerFactoryUtil;
|
||||
import ca.uhn.fhir.jpa.model.dialect.HapiFhirH2Dialect;
|
||||
import ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgres94Dialect;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
||||
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
|
||||
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
|
||||
import ca.uhn.fhir.jpa.validation.ValidationSettings;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
|
@ -22,7 +22,6 @@ import org.hibernate.search.backend.lucene.cfg.LuceneIndexSettings;
|
|||
import org.hibernate.search.engine.cfg.BackendSettings;
|
||||
import org.hl7.fhir.dstu2.model.Subscription;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -44,16 +43,11 @@ import java.util.concurrent.TimeUnit;
|
|||
@EnableTransactionManagement()
|
||||
public class TestDstu2Config {
|
||||
|
||||
public static final String FHIR_LUCENE_LOCATION_DSTU2 = "${fhir.lucene.location.dstu2}";
|
||||
public static final String FHIR_LUCENE_LOCATION_DSTU2 = "fhir.lucene.location.dstu2";
|
||||
|
||||
@Value(TestDstu3Config.FHIR_DB_USERNAME)
|
||||
private String myDbUsername;
|
||||
|
||||
@Value(TestDstu3Config.FHIR_DB_PASSWORD)
|
||||
private String myDbPassword;
|
||||
|
||||
@Value(FHIR_LUCENE_LOCATION_DSTU2)
|
||||
private String myFhirLuceneLocation;
|
||||
private String myDbUsername = System.getProperty(TestR5Config.FHIR_DB_USERNAME);
|
||||
private String myDbPassword = System.getProperty(TestR5Config.FHIR_DB_PASSWORD);
|
||||
private String myFhirLuceneLocation = System.getProperty(FHIR_LUCENE_LOCATION_DSTU2);
|
||||
|
||||
@Bean
|
||||
public PublicSecurityInterceptor securityInterceptor() {
|
||||
|
@ -88,7 +82,9 @@ public class TestDstu2Config {
|
|||
|
||||
@Bean
|
||||
public ModelConfig modelConfig() {
|
||||
return daoConfig().getModelConfig();
|
||||
ModelConfig retVal = daoConfig().getModelConfig();
|
||||
retVal.setIndexIdentifierOfType(true);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -103,7 +99,7 @@ public class TestDstu2Config {
|
|||
public DataSource dataSource() {
|
||||
BasicDataSource retVal = new BasicDataSource();
|
||||
if (CommonConfig.isLocalTestMode()) {
|
||||
retVal.setUrl("jdbc:derby:memory:fhirtest_dstu2;create=true");
|
||||
retVal.setUrl("jdbc:h2:mem:fhirtest_dstu2");
|
||||
} else {
|
||||
retVal.setDriver(new org.postgresql.Driver());
|
||||
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_dstu2");
|
||||
|
@ -144,7 +140,7 @@ public class TestDstu2Config {
|
|||
private Properties jpaProperties() {
|
||||
Properties extraProperties = new Properties();
|
||||
if (CommonConfig.isLocalTestMode()) {
|
||||
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
|
||||
extraProperties.put("hibernate.dialect", HapiFhirH2Dialect.class.getName());
|
||||
} else {
|
||||
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
||||
}
|
||||
|
@ -168,6 +164,7 @@ public class TestDstu2Config {
|
|||
|
||||
/**
|
||||
* Bean which validates incoming requests
|
||||
*
|
||||
* @param theInstanceValidator
|
||||
*/
|
||||
@Bean
|
||||
|
|
|
@ -5,12 +5,12 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
|||
import ca.uhn.fhir.jpa.config.HapiJpaConfig;
|
||||
import ca.uhn.fhir.jpa.config.dstu3.JpaDstu3Config;
|
||||
import ca.uhn.fhir.jpa.config.util.HapiEntityManagerFactoryUtil;
|
||||
import ca.uhn.fhir.jpa.model.dialect.HapiFhirH2Dialect;
|
||||
import ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgres94Dialect;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
||||
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
|
||||
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
|
||||
import ca.uhn.fhir.jpa.validation.ValidationSettings;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.IInstanceValidatorModule;
|
||||
|
@ -23,7 +23,6 @@ import org.hibernate.search.backend.lucene.cfg.LuceneIndexSettings;
|
|||
import org.hibernate.search.engine.cfg.BackendSettings;
|
||||
import org.hl7.fhir.dstu2.model.Subscription;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -45,17 +44,12 @@ import java.util.concurrent.TimeUnit;
|
|||
@EnableTransactionManagement()
|
||||
public class TestDstu3Config {
|
||||
public static final String FHIR_DB_USERNAME = "${fhir.db.username}";
|
||||
public static final String FHIR_DB_PASSWORD = "${fhir.db.password}";
|
||||
public static final String FHIR_DB_PASSWORD = "${fhir.db.password}";
|
||||
public static final String FHIR_LUCENE_LOCATION_DSTU3 = "${fhir.lucene.location.dstu3}";
|
||||
|
||||
@Value(TestDstu3Config.FHIR_DB_USERNAME)
|
||||
private String myDbUsername;
|
||||
|
||||
@Value(TestDstu3Config.FHIR_DB_PASSWORD)
|
||||
private String myDbPassword;
|
||||
|
||||
@Value(FHIR_LUCENE_LOCATION_DSTU3)
|
||||
private String myFhirLuceneLocation;
|
||||
private String myDbUsername = System.getProperty(TestR5Config.FHIR_DB_USERNAME);
|
||||
private String myDbPassword = System.getProperty(TestR5Config.FHIR_DB_PASSWORD);
|
||||
private String myFhirLuceneLocation = System.getProperty(FHIR_LUCENE_LOCATION_DSTU3);
|
||||
|
||||
@Bean
|
||||
public DaoConfig daoConfig() {
|
||||
|
@ -85,7 +79,9 @@ public class TestDstu3Config {
|
|||
|
||||
@Bean
|
||||
public ModelConfig modelConfig() {
|
||||
return daoConfig().getModelConfig();
|
||||
ModelConfig retVal = daoConfig().getModelConfig();
|
||||
retVal.setIndexIdentifierOfType(true);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
|
@ -114,7 +110,7 @@ public class TestDstu3Config {
|
|||
public DataSource dataSource() {
|
||||
BasicDataSource retVal = new BasicDataSource();
|
||||
if (CommonConfig.isLocalTestMode()) {
|
||||
retVal.setUrl("jdbc:derby:memory:fhirtest_dstu3;create=true");
|
||||
retVal.setUrl("jdbc:h2:mem:fhirtest_dstu3");
|
||||
} else {
|
||||
retVal.setDriver(new org.postgresql.Driver());
|
||||
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_dstu3");
|
||||
|
@ -147,7 +143,7 @@ public class TestDstu3Config {
|
|||
private Properties jpaProperties() {
|
||||
Properties extraProperties = new Properties();
|
||||
if (CommonConfig.isLocalTestMode()) {
|
||||
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
|
||||
extraProperties.put("hibernate.dialect", HapiFhirH2Dialect.class.getName());
|
||||
} else {
|
||||
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
||||
}
|
||||
|
@ -171,6 +167,7 @@ public class TestDstu3Config {
|
|||
|
||||
/**
|
||||
* Bean which validates incoming requests
|
||||
*
|
||||
* @param theFhirInstanceValidator
|
||||
*/
|
||||
@Bean
|
||||
|
|
|
@ -5,12 +5,12 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
|||
import ca.uhn.fhir.jpa.config.HapiJpaConfig;
|
||||
import ca.uhn.fhir.jpa.config.r4.JpaR4Config;
|
||||
import ca.uhn.fhir.jpa.config.util.HapiEntityManagerFactoryUtil;
|
||||
import ca.uhn.fhir.jpa.model.dialect.HapiFhirH2Dialect;
|
||||
import ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgres94Dialect;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
||||
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
|
||||
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
|
||||
import ca.uhn.fhir.jpa.validation.ValidationSettings;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.IInstanceValidatorModule;
|
||||
|
@ -23,7 +23,6 @@ import org.hibernate.search.backend.lucene.cfg.LuceneIndexSettings;
|
|||
import org.hibernate.search.engine.cfg.BackendSettings;
|
||||
import org.hl7.fhir.dstu2.model.Subscription;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -49,14 +48,9 @@ public class TestR4Config {
|
|||
public static final String FHIR_LUCENE_LOCATION_R4 = "${fhir.lucene.location.r4}";
|
||||
public static final Integer COUNT_SEARCH_RESULTS_UP_TO = 50000;
|
||||
|
||||
@Value(TestR4Config.FHIR_DB_USERNAME)
|
||||
private String myDbUsername;
|
||||
|
||||
@Value(TestR4Config.FHIR_DB_PASSWORD)
|
||||
private String myDbPassword;
|
||||
|
||||
@Value(FHIR_LUCENE_LOCATION_R4)
|
||||
private String myFhirLuceneLocation;
|
||||
private String myDbUsername = System.getProperty(TestR5Config.FHIR_DB_USERNAME);
|
||||
private String myDbPassword = System.getProperty(TestR5Config.FHIR_DB_PASSWORD);
|
||||
private String myFhirLuceneLocation = System.getProperty(FHIR_LUCENE_LOCATION_R4);
|
||||
|
||||
@Bean
|
||||
public DaoConfig daoConfig() {
|
||||
|
@ -85,7 +79,9 @@ public class TestR4Config {
|
|||
|
||||
@Bean
|
||||
public ModelConfig modelConfig() {
|
||||
return daoConfig().getModelConfig();
|
||||
ModelConfig retVal = daoConfig().getModelConfig();
|
||||
retVal.setIndexIdentifierOfType(true);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
|
@ -101,7 +97,7 @@ public class TestR4Config {
|
|||
public DataSource dataSource() {
|
||||
BasicDataSource retVal = new BasicDataSource();
|
||||
if (CommonConfig.isLocalTestMode()) {
|
||||
retVal.setUrl("jdbc:derby:memory:fhirtest_r4;create=true");
|
||||
retVal.setUrl("jdbc:h2:mem:fhirtest_r4");
|
||||
} else {
|
||||
retVal.setDriver(new org.postgresql.Driver());
|
||||
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_r4");
|
||||
|
@ -142,7 +138,7 @@ public class TestR4Config {
|
|||
private Properties jpaProperties() {
|
||||
Properties extraProperties = new Properties();
|
||||
if (CommonConfig.isLocalTestMode()) {
|
||||
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
|
||||
extraProperties.put("hibernate.dialect", HapiFhirH2Dialect.class.getName());
|
||||
} else {
|
||||
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
||||
}
|
||||
|
@ -165,6 +161,7 @@ public class TestR4Config {
|
|||
|
||||
/**
|
||||
* Bean which validates incoming requests
|
||||
*
|
||||
* @param theFhirInstanceValidator
|
||||
*/
|
||||
@Bean
|
||||
|
@ -202,5 +199,4 @@ public class TestR4Config {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
|||
import ca.uhn.fhir.jpa.config.HapiJpaConfig;
|
||||
import ca.uhn.fhir.jpa.config.r5.JpaR5Config;
|
||||
import ca.uhn.fhir.jpa.config.util.HapiEntityManagerFactoryUtil;
|
||||
import ca.uhn.fhir.jpa.model.dialect.HapiFhirH2Dialect;
|
||||
import ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgres94Dialect;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
||||
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
|
||||
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
|
||||
import ca.uhn.fhir.jpa.validation.ValidationSettings;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.IInstanceValidatorModule;
|
||||
|
@ -23,7 +23,8 @@ import org.hibernate.search.backend.lucene.cfg.LuceneIndexSettings;
|
|||
import org.hibernate.search.engine.cfg.BackendSettings;
|
||||
import org.hl7.fhir.dstu2.model.Subscription;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -48,15 +49,10 @@ public class TestR5Config {
|
|||
public static final String FHIR_DB_PASSWORD = "${fhir.db.password}";
|
||||
public static final String FHIR_LUCENE_LOCATION_R5 = "${fhir.lucene.location.r5}";
|
||||
public static final Integer COUNT_SEARCH_RESULTS_UP_TO = 50000;
|
||||
|
||||
@Value(TestR5Config.FHIR_DB_USERNAME)
|
||||
private String myDbUsername;
|
||||
|
||||
@Value(TestR5Config.FHIR_DB_PASSWORD)
|
||||
private String myDbPassword;
|
||||
|
||||
@Value(FHIR_LUCENE_LOCATION_R5)
|
||||
private String myFhirLuceneLocation;
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(TestR5Config.class);
|
||||
private String myDbUsername = System.getProperty(TestR5Config.FHIR_DB_USERNAME);
|
||||
private String myDbPassword = System.getProperty(TestR5Config.FHIR_DB_PASSWORD);
|
||||
private String myFhirLuceneLocation = System.getProperty(FHIR_LUCENE_LOCATION_R5);
|
||||
|
||||
@Bean
|
||||
public DaoConfig daoConfig() {
|
||||
|
@ -85,7 +81,9 @@ public class TestR5Config {
|
|||
|
||||
@Bean
|
||||
public ModelConfig modelConfig() {
|
||||
return daoConfig().getModelConfig();
|
||||
ModelConfig retVal = daoConfig().getModelConfig();
|
||||
retVal.setIndexIdentifierOfType(true);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -97,9 +95,12 @@ public class TestR5Config {
|
|||
|
||||
@Bean(name = "myPersistenceDataSourceR5")
|
||||
public DataSource dataSource() {
|
||||
ourLog.info("Starting R5 database with DB username: {}", myDbUsername);
|
||||
ourLog.info("Have system property username: {}", System.getProperty(FHIR_DB_USERNAME));
|
||||
|
||||
BasicDataSource retVal = new BasicDataSource();
|
||||
if (CommonConfig.isLocalTestMode()) {
|
||||
retVal.setUrl("jdbc:derby:memory:fhirtest_r5;create=true");
|
||||
retVal.setUrl("jdbc:h2:mem:fhirtest_r5");
|
||||
} else {
|
||||
retVal.setDriver(new org.postgresql.Driver());
|
||||
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_r5");
|
||||
|
@ -141,7 +142,7 @@ public class TestR5Config {
|
|||
private Properties jpaProperties() {
|
||||
Properties extraProperties = new Properties();
|
||||
if (CommonConfig.isLocalTestMode()) {
|
||||
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
|
||||
extraProperties.put("hibernate.dialect", HapiFhirH2Dialect.class.getName());
|
||||
} else {
|
||||
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
||||
}
|
||||
|
@ -165,6 +166,7 @@ public class TestR5Config {
|
|||
|
||||
/**
|
||||
* Bean which validates incoming requests
|
||||
*
|
||||
* @param theFhirInstanceValidator
|
||||
*/
|
||||
@Bean
|
||||
|
@ -202,5 +204,4 @@ public class TestR5Config {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.i18n.Msg;
|
|||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.rest.annotation.GraphQL;
|
||||
|
@ -32,6 +33,7 @@ import ca.uhn.fhir.rest.annotation.GraphQLQueryUrl;
|
|||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Initialize;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
@ -39,12 +41,12 @@ import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException;
|
|||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.utilities.graphql.IGraphQLEngine;
|
||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||
import org.hl7.fhir.utilities.graphql.ObjectValue;
|
||||
import org.hl7.fhir.utilities.graphql.Package;
|
||||
import org.hl7.fhir.utilities.graphql.Parser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -54,9 +56,10 @@ import javax.annotation.Nullable;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
public class GraphQLProvider {
|
||||
private final Supplier<IGraphQLEngine> engineFactory;
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(GraphQLProvider.class);
|
||||
|
||||
private final Supplier<IGraphQLEngine> myEngineFactory;
|
||||
private final IGraphQLStorageServices myStorageServices;
|
||||
private Logger ourLog = LoggerFactory.getLogger(GraphQLProvider.class);
|
||||
|
||||
/**
|
||||
* Constructor which uses a default context and validation support object
|
||||
|
@ -83,21 +86,21 @@ public class GraphQLProvider {
|
|||
IValidationSupport validationSupport = theValidationSupport;
|
||||
validationSupport = ObjectUtils.defaultIfNull(validationSupport, new DefaultProfileValidationSupport(theFhirContext));
|
||||
org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext workerContext = new org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext(theFhirContext, validationSupport);
|
||||
engineFactory = () -> new org.hl7.fhir.dstu3.utils.GraphQLEngine(workerContext);
|
||||
myEngineFactory = () -> new org.hl7.fhir.dstu3.utils.GraphQLEngine(workerContext);
|
||||
break;
|
||||
}
|
||||
case R4: {
|
||||
IValidationSupport validationSupport = theValidationSupport;
|
||||
validationSupport = ObjectUtils.defaultIfNull(validationSupport, new DefaultProfileValidationSupport(theFhirContext));
|
||||
org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext workerContext = new org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext(theFhirContext, validationSupport);
|
||||
engineFactory = () -> new org.hl7.fhir.r4.utils.GraphQLEngine(workerContext);
|
||||
myEngineFactory = () -> new org.hl7.fhir.r4.utils.GraphQLEngine(workerContext);
|
||||
break;
|
||||
}
|
||||
case R5: {
|
||||
IValidationSupport validationSupport = theValidationSupport;
|
||||
validationSupport = ObjectUtils.defaultIfNull(validationSupport, new DefaultProfileValidationSupport(theFhirContext));
|
||||
org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext workerContext = new org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext(theFhirContext, validationSupport);
|
||||
engineFactory = () -> new org.hl7.fhir.r5.utils.GraphQLEngine(workerContext);
|
||||
myEngineFactory = () -> new org.hl7.fhir.r5.utils.GraphQLEngine(workerContext);
|
||||
break;
|
||||
}
|
||||
case DSTU2:
|
||||
|
@ -111,8 +114,8 @@ public class GraphQLProvider {
|
|||
myStorageServices = theStorageServices;
|
||||
}
|
||||
|
||||
@Description(value="This operation invokes a GraphQL expression for fetching an joining a graph of resources, returning them in a custom format.")
|
||||
@GraphQL(type=RequestTypeEnum.GET)
|
||||
@Description(value = "This operation invokes a GraphQL expression for fetching an joining a graph of resources, returning them in a custom format.")
|
||||
@GraphQL(type = RequestTypeEnum.GET)
|
||||
public String processGraphQlGetRequest(ServletRequestDetails theRequestDetails, @IdParam IIdType theId, @GraphQLQueryUrl String theQueryUrl) {
|
||||
if (theQueryUrl != null) {
|
||||
return processGraphQLRequest(theRequestDetails, theId, theQueryUrl);
|
||||
|
@ -120,24 +123,31 @@ public class GraphQLProvider {
|
|||
throw new InvalidRequestException(Msg.code(1144) + "Unable to parse empty GraphQL expression");
|
||||
}
|
||||
|
||||
@Description(value="This operation invokes a GraphQL expression for fetching an joining a graph of resources, returning them in a custom format.")
|
||||
@GraphQL(type=RequestTypeEnum.POST)
|
||||
public String processGraphQlPostRequest(ServletRequestDetails theRequestDetails, @IdParam IIdType theId, @GraphQLQueryBody String theQueryBody) {
|
||||
@Description(value = "This operation invokes a GraphQL expression for fetching an joining a graph of resources, returning them in a custom format.")
|
||||
@GraphQL(type = RequestTypeEnum.POST)
|
||||
public String processGraphQlPostRequest(ServletRequestDetails theServletRequestDetails, RequestDetails theRequestDetails, @IdParam IIdType theId, @GraphQLQueryBody String theQueryBody) {
|
||||
if (theQueryBody != null) {
|
||||
return processGraphQLRequest(theRequestDetails, theId, theQueryBody);
|
||||
return processGraphQLRequest(theServletRequestDetails, theId, theQueryBody);
|
||||
}
|
||||
throw new InvalidRequestException(Msg.code(1145) + "Unable to parse empty GraphQL expression");
|
||||
}
|
||||
|
||||
public String processGraphQLRequest(ServletRequestDetails theRequestDetails, IIdType theId, String theQuery) {
|
||||
IGraphQLEngine engine = engineFactory.get();
|
||||
Package parsedGraphQLRequest;
|
||||
try {
|
||||
parsedGraphQLRequest = Parser.parse(theQuery);
|
||||
} catch (Exception e) {
|
||||
throw new InvalidRequestException(Msg.code(1146) + "Unable to parse GraphQL Expression: " + e);
|
||||
}
|
||||
|
||||
return processGraphQLRequest(theRequestDetails, theId, parsedGraphQLRequest);
|
||||
}
|
||||
|
||||
protected String processGraphQLRequest(ServletRequestDetails theRequestDetails, IIdType theId, Package parsedGraphQLRequest) {
|
||||
IGraphQLEngine engine = myEngineFactory.get();
|
||||
engine.setAppInfo(theRequestDetails);
|
||||
engine.setServices(myStorageServices);
|
||||
try {
|
||||
engine.setGraphQL(Parser.parse(theQuery));
|
||||
} catch (Exception theE) {
|
||||
throw new InvalidRequestException(Msg.code(1146) + "Unable to parse GraphQL Expression: " + theE.toString());
|
||||
}
|
||||
engine.setGraphQL(parsedGraphQLRequest);
|
||||
|
||||
try {
|
||||
|
||||
|
@ -167,7 +177,7 @@ public class GraphQLProvider {
|
|||
ourLog.error("Failure during GraphQL processing", e);
|
||||
}
|
||||
b.append(e.getMessage());
|
||||
throw new UnclassifiedServerFailureException(statusCode, Msg.code(1147) + b.toString());
|
||||
throw new UnclassifiedServerFailureException(statusCode, Msg.code(1147) + b);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ import static org.mockito.Mockito.when;
|
|||
|
||||
public class LoggingInterceptorTest {
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static final FhirContext ourCtx = FhirContext.forR4Cached();
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private Logger myLoggerRoot;
|
||||
|
|
|
@ -8,10 +8,10 @@ import ca.uhn.fhir.rest.annotation.IdParam;
|
|||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -22,9 +22,6 @@ import org.apache.http.entity.StringEntity;
|
|||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.HumanName;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
|
@ -33,10 +30,10 @@ import org.junit.jupiter.api.AfterAll;
|
|||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -44,63 +41,37 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public class GraphQLR4RawTest {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GraphQLR4RawTest.class);
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static final FhirContext ourCtx = FhirContext.forR4Cached();
|
||||
private static String ourNextRetVal;
|
||||
private static IdType ourLastId;
|
||||
private static String ourLastQuery;
|
||||
private static int ourMethodCount;
|
||||
private static String ourLastResourceType;
|
||||
|
||||
@AfterAll
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
JettyUtil.closeServer(ourServer);
|
||||
TestUtil.randomizeLocaleAndTimezone();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
ourServer = new Server(0);
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||
|
||||
servlet.registerProviders(Collections.singletonList(new MyGraphQLProvider()));
|
||||
servlet.registerProvider(new MyPatientResourceProvider());
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
JettyUtil.startServer(ourServer);
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
@RegisterExtension
|
||||
private final RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(ourCtx)
|
||||
.registerProvider(new MyPatientResourceProvider())
|
||||
.registerProvider(new MyGraphQLProvider());
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
ourNextRetVal = null;
|
||||
ourLastId = null;
|
||||
ourLastQuery = null;
|
||||
ourMethodCount = 0;
|
||||
ourLastResourceType = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGraphInstance() throws Exception {
|
||||
public void testGraphInstance_Get() throws Exception {
|
||||
ourNextRetVal = "{\"foo\"}";
|
||||
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
|
@ -118,12 +89,29 @@ public class GraphQLR4RawTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGraphPostContentTypeJson() throws Exception {
|
||||
public void testGraphInstance_Get_UnsupportedResourceType() throws Exception {
|
||||
ourNextRetVal = "{\"foo\"}";
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$graphql");
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/Condition/123/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(404, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("Unknown resource type"));
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGraphInstance_Post_ContentTypeJson() throws Exception {
|
||||
ourNextRetVal = "{\"foo\"}";
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + myRestfulServerExtension.getPort() + "/Patient/123/$graphql");
|
||||
StringEntity entity = new StringEntity("{\"query\": \"{name{family,given}}\"}");
|
||||
httpPost.setEntity(entity);
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
|
@ -147,10 +135,10 @@ public class GraphQLR4RawTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGraphPostContentTypeGraphql() throws Exception {
|
||||
public void testGraphInstance_Post_ContentTypeGraphql() throws Exception {
|
||||
ourNextRetVal = "{\"foo\"}";
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/123/$graphql");
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + myRestfulServerExtension.getPort() + "/Patient/123/$graphql");
|
||||
StringEntity entity = new StringEntity("{name{family,given}}");
|
||||
httpPost.setEntity(entity);
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
|
@ -166,6 +154,7 @@ public class GraphQLR4RawTest {
|
|||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
||||
assertEquals("Patient/123", ourLastId.getValue());
|
||||
assertEquals("{name{family,given}}", ourLastQuery);
|
||||
assertEquals("Patient", ourLastResourceType);
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
@ -173,31 +162,41 @@ public class GraphQLR4RawTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGraphInstanceUnknownType() throws Exception {
|
||||
public void testGraphBase_Post_ListQuery() throws Exception {
|
||||
ourNextRetVal = "{\"foo\"}";
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + myRestfulServerExtension.getPort() + "/$graphql");
|
||||
StringEntity entity = new StringEntity("{\"query\": \"{PatientList(date: \\\"2022\\\") {name{family,given}}}\"}");
|
||||
httpPost.setEntity(entity);
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
httpPost.setHeader("Content-type", "application/json");
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Condition/123/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(404, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("Unknown resource type"));
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("{\"foo\"}", responseContent);
|
||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
||||
assertNull(ourLastId);
|
||||
assertNull(ourLastResourceType);
|
||||
assertEquals("{PatientList(date: \"2022\") {name{family,given}}}", ourLastQuery);
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGraphSystem() throws Exception {
|
||||
ourNextRetVal = "{\"foo\"}";
|
||||
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/$graphql?query=" + UrlUtil.escapeUrlParam("{name{family,given}}"));
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
|
@ -215,20 +214,33 @@ public class GraphQLR4RawTest {
|
|||
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourClient.close();
|
||||
TestUtil.randomizeLocaleAndTimezone();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
}
|
||||
|
||||
public static class MyGraphQLProvider {
|
||||
|
||||
@GraphQL(type=RequestTypeEnum.GET)
|
||||
@GraphQL(type = RequestTypeEnum.GET)
|
||||
public String processGet(@IdParam IdType theId, @GraphQLQueryUrl String theQuery) {
|
||||
ourMethodCount++;
|
||||
ourLastId = theId;
|
||||
ourLastQuery = theQuery;
|
||||
return ourNextRetVal;
|
||||
}
|
||||
|
||||
@GraphQL(type=RequestTypeEnum.POST)
|
||||
public String processPost(@IdParam IdType theId, @GraphQLQueryBody String theQuery) {
|
||||
ourMethodCount++;
|
||||
@GraphQL(type = RequestTypeEnum.POST)
|
||||
public String processPost(RequestDetails theRequestDetails, @IdParam IdType theId, @GraphQLQueryBody String theQuery) {
|
||||
ourLastId = theId;
|
||||
ourLastResourceType = theRequestDetails.getResourceName();
|
||||
ourLastQuery = theQuery;
|
||||
return ourNextRetVal;
|
||||
}
|
||||
|
@ -246,13 +258,13 @@ public class GraphQLR4RawTest {
|
|||
@Search()
|
||||
public List search(
|
||||
@OptionalParam(name = Patient.SP_IDENTIFIER) TokenAndListParam theIdentifiers) {
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
ArrayList<Patient> retVal = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 200; i++) {
|
||||
Patient patient = new Patient();
|
||||
patient.addName(new HumanName().setFamily("FAMILY"));
|
||||
patient.getIdElement().setValue("Patient/" + i);
|
||||
retVal.add((Patient) patient);
|
||||
retVal.add(patient);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@ package ca.uhn.fhir.util;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r4.model.DateTimeType;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Period;
|
||||
import org.hl7.fhir.r4.model.Quantity;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
|
@ -88,6 +90,53 @@ public class GraphQLEngineTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testChoiceType_SelectDifferentType() throws EGraphEngine, EGraphQLException, IOException {
|
||||
Observation obs = new Observation();
|
||||
obs.setId("http://foo.com/Patient/PATA");
|
||||
obs.setEffective(new Period().setStartElement(new DateTimeType("2022-01-01T00:00:00Z")).setEndElement(new DateTimeType("2022-01-01T05:00:00Z")));
|
||||
|
||||
GraphQLEngine engine = new GraphQLEngine(ourWorkerCtx);
|
||||
engine.setFocus(obs);
|
||||
engine.setGraphQL(Parser.parse("{id, effectiveDateTime}"));
|
||||
engine.execute();
|
||||
|
||||
GraphQLResponse output = engine.getOutput();
|
||||
output.setWriteWrapper(false);
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
output.write(outputBuilder, 0, "\n");
|
||||
|
||||
String expected = "{\n" +
|
||||
" \"id\":\"http://foo.com/Patient/PATA\"\n" +
|
||||
"}";
|
||||
assertEquals(TestUtil.stripReturns(expected), TestUtil.stripReturns(outputBuilder.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChoiceType_SelectSameType() throws EGraphEngine, EGraphQLException, IOException {
|
||||
Observation obs = new Observation();
|
||||
obs.setId("http://foo.com/Patient/PATA");
|
||||
obs.setEffective(new DateTimeType("2022-01-01T12:12:12Z"));
|
||||
|
||||
GraphQLEngine engine = new GraphQLEngine(ourWorkerCtx);
|
||||
engine.setFocus(obs);
|
||||
engine.setGraphQL(Parser.parse("{id, effectiveDateTime}"));
|
||||
engine.execute();
|
||||
|
||||
GraphQLResponse output = engine.getOutput();
|
||||
output.setWriteWrapper(false);
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
output.write(outputBuilder, 0, "\n");
|
||||
|
||||
String expected = "{\n" +
|
||||
" \"id\":\"http://foo.com/Patient/PATA\",\n" +
|
||||
" \"effectiveDateTime\":\"2022-01-01T12:12:12Z\"\n" +
|
||||
"}";
|
||||
assertEquals(TestUtil.stripReturns(expected), TestUtil.stripReturns(outputBuilder.toString()));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReferences() throws EGraphQLException, EGraphEngine, IOException, FHIRException {
|
||||
|
||||
|
@ -128,7 +177,7 @@ public class GraphQLEngineTest {
|
|||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
ourCtx = FhirContext.forR4();
|
||||
ourCtx = FhirContext.forR4Cached();
|
||||
ourWorkerCtx = new HapiWorkerContext(ourCtx, ourCtx.getValidationSupport());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
package org.hl7.fhir.r5.utils;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r5.model.DateTimeType;
|
||||
import org.hl7.fhir.r5.model.Observation;
|
||||
import org.hl7.fhir.r5.model.Patient;
|
||||
import org.hl7.fhir.r5.model.Period;
|
||||
import org.hl7.fhir.r5.model.Quantity;
|
||||
import org.hl7.fhir.r5.model.Reference;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.utilities.graphql.EGraphEngine;
|
||||
import org.hl7.fhir.utilities.graphql.EGraphQLException;
|
||||
import org.hl7.fhir.utilities.graphql.GraphQLResponse;
|
||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||
import org.hl7.fhir.utilities.graphql.Parser;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class GraphQLEngineTest {
|
||||
private static HapiWorkerContext ourWorkerCtx;
|
||||
private static FhirContext ourCtx;
|
||||
private org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GraphQLEngineTest.class);
|
||||
|
||||
private Observation createObservation() {
|
||||
Observation obs = new Observation();
|
||||
obs.setId("http://foo.com/Patient/PATA");
|
||||
obs.setValue(new Quantity().setValue(123).setUnit("cm"));
|
||||
obs.setSubject(new Reference("Patient/123"));
|
||||
return obs;
|
||||
}
|
||||
|
||||
private IGraphQLStorageServices createStorageServices() throws FHIRException {
|
||||
IGraphQLStorageServices retVal = mock(IGraphQLStorageServices.class);
|
||||
when(retVal.lookup(nullable(Object.class), nullable(Resource.class), nullable(Reference.class))).thenAnswer(new Answer<Object>() {
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) {
|
||||
Object appInfo = invocation.getArguments()[0];
|
||||
Resource context = (Resource) invocation.getArguments()[1];
|
||||
Reference reference = (Reference) invocation.getArguments()[2];
|
||||
ourLog.info("AppInfo: {} / Context: {} / Reference: {}", appInfo, context.getId(), reference.getReference());
|
||||
|
||||
if (reference.getReference().equalsIgnoreCase("Patient/123")) {
|
||||
Patient p = new Patient();
|
||||
p.getBirthDateElement().setValueAsString("2011-02-22");
|
||||
return new IGraphQLStorageServices.ReferenceResolution(context, p);
|
||||
}
|
||||
|
||||
ourLog.info("Not found!");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGraphSimple() throws EGraphQLException, EGraphEngine, IOException, FHIRException {
|
||||
|
||||
Observation obs = createObservation();
|
||||
|
||||
GraphQLEngine engine = new GraphQLEngine(ourWorkerCtx);
|
||||
engine.setFocus(obs);
|
||||
engine.setGraphQL(Parser.parse("{valueQuantity{value,unit}}"));
|
||||
engine.execute();
|
||||
|
||||
GraphQLResponse output = engine.getOutput();
|
||||
output.setWriteWrapper(false);
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
output.write(outputBuilder, 0, "\n");
|
||||
|
||||
String expected = "{\n" +
|
||||
" \"valueQuantity\":{\n" +
|
||||
" \"value\":123,\n" +
|
||||
" \"unit\":\"cm\"\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
assertEquals(TestUtil.stripReturns(expected), TestUtil.stripReturns(outputBuilder.toString()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testChoiceType_SelectDifferentType() throws EGraphEngine, EGraphQLException, IOException {
|
||||
Observation obs = new Observation();
|
||||
obs.setId("http://foo.com/Patient/PATA");
|
||||
obs.setEffective(new Period().setStartElement(new DateTimeType("2022-01-01T00:00:00Z")).setEndElement(new DateTimeType("2022-01-01T05:00:00Z")));
|
||||
|
||||
GraphQLEngine engine = new GraphQLEngine(ourWorkerCtx);
|
||||
engine.setFocus(obs);
|
||||
engine.setGraphQL(Parser.parse("{id, effectiveDateTime}"));
|
||||
engine.execute();
|
||||
|
||||
GraphQLResponse output = engine.getOutput();
|
||||
output.setWriteWrapper(false);
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
output.write(outputBuilder, 0, "\n");
|
||||
|
||||
String expected = "{\n" +
|
||||
" \"id\":\"http://foo.com/Patient/PATA\"\n" +
|
||||
"}";
|
||||
assertEquals(TestUtil.stripReturns(expected), TestUtil.stripReturns(outputBuilder.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChoiceType_SelectSameType() throws EGraphEngine, EGraphQLException, IOException {
|
||||
Observation obs = new Observation();
|
||||
obs.setId("http://foo.com/Patient/PATA");
|
||||
obs.setEffective(new DateTimeType("2022-01-01T12:12:12Z"));
|
||||
|
||||
GraphQLEngine engine = new GraphQLEngine(ourWorkerCtx);
|
||||
engine.setFocus(obs);
|
||||
engine.setGraphQL(Parser.parse("{id, effectiveDateTime}"));
|
||||
engine.execute();
|
||||
|
||||
GraphQLResponse output = engine.getOutput();
|
||||
output.setWriteWrapper(false);
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
output.write(outputBuilder, 0, "\n");
|
||||
|
||||
String expected = "{\n" +
|
||||
" \"id\":\"http://foo.com/Patient/PATA\",\n" +
|
||||
" \"effectiveDateTime\":\"2022-01-01T12:12:12Z\"\n" +
|
||||
"}";
|
||||
assertEquals(TestUtil.stripReturns(expected), TestUtil.stripReturns(outputBuilder.toString()));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReferences() throws EGraphQLException, EGraphEngine, IOException, FHIRException {
|
||||
|
||||
String graph = " { \n" +
|
||||
" id\n" +
|
||||
" subject { \n" +
|
||||
" reference\n" +
|
||||
" resource(type : Patient) { birthDate }\n" +
|
||||
" resource(type : Practioner) { practitionerRole { speciality } }\n" +
|
||||
" } \n" +
|
||||
" code {coding {system code} }\n" +
|
||||
" }\n" +
|
||||
" ";
|
||||
|
||||
GraphQLEngine engine = new GraphQLEngine(ourWorkerCtx);
|
||||
engine.setFocus(createObservation());
|
||||
engine.setGraphQL(Parser.parse(graph));
|
||||
engine.setServices(createStorageServices());
|
||||
engine.execute();
|
||||
|
||||
GraphQLResponse output = engine.getOutput();
|
||||
output.setWriteWrapper(false);
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
output.write(outputBuilder, 0, "\n");
|
||||
|
||||
String expected = "{\n" +
|
||||
" \"id\":\"http://foo.com/Patient/PATA\",\n" +
|
||||
" \"subject\":{\n" +
|
||||
" \"reference\":\"Patient/123\",\n" +
|
||||
" \"resource\":{\n" +
|
||||
" \"birthDate\":\"2011-02-22\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
assertEquals(TestUtil.stripReturns(expected), TestUtil.stripReturns(outputBuilder.toString()));
|
||||
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
ourCtx = FhirContext.forR5Cached();
|
||||
ourWorkerCtx = new HapiWorkerContext(ourCtx, ourCtx.getValidationSupport());
|
||||
}
|
||||
|
||||
}
|
16
pom.xml
16
pom.xml
|
@ -45,15 +45,6 @@
|
|||
</scm>
|
||||
|
||||
<repositories>
|
||||
<!--
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
-->
|
||||
<repository>
|
||||
<id>oss-snapshot</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
|
@ -765,7 +756,7 @@
|
|||
|
||||
<properties>
|
||||
|
||||
<fhir_core_version>5.6.27</fhir_core_version>
|
||||
<fhir_core_version>5.6.35</fhir_core_version>
|
||||
<ucum_version>1.0.3</ucum_version>
|
||||
|
||||
<surefire_jvm_args>-Dfile.encoding=UTF-8 -Xmx2048m</surefire_jvm_args>
|
||||
|
@ -924,6 +915,11 @@
|
|||
<artifactId>caffeine</artifactId>
|
||||
<version>${caffeine_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.graphql-java</groupId>
|
||||
<artifactId>graphql-java</artifactId>
|
||||
<version>17.3</version>
|
||||
</dependency>
|
||||
<!-- mail start -->
|
||||
<dependency>
|
||||
<groupId>org.simplejavamail</groupId>
|
||||
|
|
Loading…
Reference in New Issue