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
|
* IMPORTANT: Please update the following comment after you add a new code
|
||||||
* Last code value: 2034
|
* Last code value: 2036
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private Msg() {}
|
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%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.io.CharArrayWriter;
|
import java.io.CharArrayWriter;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.Normalizer;
|
import java.text.Normalizer;
|
||||||
|
@ -105,4 +106,13 @@ public class StringUtil {
|
||||||
return theString.substring(0, theString.offsetByCodePoints(0, theCodePointCount));
|
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////", '/'));
|
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>
|
<name>HAPI FHIR JPA Server</name>
|
||||||
|
|
||||||
<dependencies>
|
<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>
|
<dependency>
|
||||||
<groupId>com.fasterxml.woodstox</groupId>
|
<groupId>com.fasterxml.woodstox</groupId>
|
||||||
|
@ -174,6 +156,12 @@
|
||||||
<artifactId>javassist</artifactId>
|
<artifactId>javassist</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- GraphQL -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.graphql-java</groupId>
|
||||||
|
<artifactId>graphql-java</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- SQL Builder -->
|
<!-- SQL Builder -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.healthmarketscience.sqlbuilder</groupId>
|
<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.FhirContext;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
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.api.dao.IFhirSystemDao;
|
||||||
import ca.uhn.fhir.jpa.config.GeneratedDaoAndResourceProviderConfigDstu3;
|
import ca.uhn.fhir.jpa.config.GeneratedDaoAndResourceProviderConfigDstu3;
|
||||||
import ca.uhn.fhir.jpa.config.JpaConfig;
|
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.ITransactionProcessorVersionAdapter;
|
||||||
import ca.uhn.fhir.jpa.dao.dstu3.TransactionProcessorVersionAdapterDstu3;
|
import ca.uhn.fhir.jpa.dao.dstu3.TransactionProcessorVersionAdapterDstu3;
|
||||||
import ca.uhn.fhir.jpa.graphql.GraphQLProvider;
|
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.TermLoaderSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.term.TermReadSvcDstu3;
|
import ca.uhn.fhir.jpa.term.TermReadSvcDstu3;
|
||||||
import ca.uhn.fhir.jpa.term.TermVersionAdapterSvcDstu3;
|
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.ITermLoaderSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvcDstu3;
|
import ca.uhn.fhir.jpa.term.api.ITermReadSvcDstu3;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
|
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.Bundle;
|
||||||
import org.hl7.fhir.dstu3.model.Meta;
|
import org.hl7.fhir.dstu3.model.Meta;
|
||||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||||
|
@ -62,8 +65,8 @@ public class JpaDstu3Config {
|
||||||
|
|
||||||
@Bean(name = JpaConfig.GRAPHQL_PROVIDER_NAME)
|
@Bean(name = JpaConfig.GRAPHQL_PROVIDER_NAME)
|
||||||
@Lazy
|
@Lazy
|
||||||
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport) {
|
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport, ISearchParamRegistry theSearchParamRegistry, IDaoRegistry theDaoRegistry) {
|
||||||
return new GraphQLProvider(theFhirContext, theValidationSupport, theGraphqlStorageServices);
|
return new GraphQLProviderWithIntrospection(theFhirContext, theValidationSupport, theGraphqlStorageServices, theSearchParamRegistry, theDaoRegistry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.config.r4;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
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.api.dao.IFhirSystemDao;
|
||||||
import ca.uhn.fhir.jpa.config.GeneratedDaoAndResourceProviderConfigR4;
|
import ca.uhn.fhir.jpa.config.GeneratedDaoAndResourceProviderConfigR4;
|
||||||
import ca.uhn.fhir.jpa.config.JpaConfig;
|
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.ITransactionProcessorVersionAdapter;
|
||||||
import ca.uhn.fhir.jpa.dao.r4.TransactionProcessorVersionAdapterR4;
|
import ca.uhn.fhir.jpa.dao.r4.TransactionProcessorVersionAdapterR4;
|
||||||
import ca.uhn.fhir.jpa.graphql.GraphQLProvider;
|
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.TermLoaderSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.term.TermReadSvcR4;
|
import ca.uhn.fhir.jpa.term.TermReadSvcR4;
|
||||||
import ca.uhn.fhir.jpa.term.TermVersionAdapterSvcR4;
|
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.ITermLoaderSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvcR4;
|
import ca.uhn.fhir.jpa.term.api.ITermReadSvcR4;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
|
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.Bundle;
|
||||||
import org.hl7.fhir.r4.model.Meta;
|
import org.hl7.fhir.r4.model.Meta;
|
||||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
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.context.annotation.Lazy;
|
||||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
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
|
@Configuration
|
||||||
@EnableTransactionManagement
|
@EnableTransactionManagement
|
||||||
@Import({
|
@Import({
|
||||||
|
@ -48,8 +71,8 @@ public class JpaR4Config {
|
||||||
|
|
||||||
@Bean(name = JpaConfig.GRAPHQL_PROVIDER_NAME)
|
@Bean(name = JpaConfig.GRAPHQL_PROVIDER_NAME)
|
||||||
@Lazy
|
@Lazy
|
||||||
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport) {
|
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport, ISearchParamRegistry theSearchParamRegistry, IDaoRegistry theDaoRegistry) {
|
||||||
return new GraphQLProvider(theFhirContext, theValidationSupport, theGraphqlStorageServices);
|
return new GraphQLProviderWithIntrospection(theFhirContext, theValidationSupport, theGraphqlStorageServices, theSearchParamRegistry, theDaoRegistry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "mySystemDaoR4")
|
@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.FhirContext;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
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.api.dao.IFhirSystemDao;
|
||||||
import ca.uhn.fhir.jpa.config.GeneratedDaoAndResourceProviderConfigR5;
|
import ca.uhn.fhir.jpa.config.GeneratedDaoAndResourceProviderConfigR5;
|
||||||
import ca.uhn.fhir.jpa.config.JpaConfig;
|
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.ITransactionProcessorVersionAdapter;
|
||||||
import ca.uhn.fhir.jpa.dao.r5.TransactionProcessorVersionAdapterR5;
|
import ca.uhn.fhir.jpa.dao.r5.TransactionProcessorVersionAdapterR5;
|
||||||
import ca.uhn.fhir.jpa.graphql.GraphQLProvider;
|
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.TermLoaderSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.term.TermReadSvcR5;
|
import ca.uhn.fhir.jpa.term.TermReadSvcR5;
|
||||||
import ca.uhn.fhir.jpa.term.TermVersionAdapterSvcR5;
|
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.ITermLoaderSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvcR5;
|
import ca.uhn.fhir.jpa.term.api.ITermReadSvcR5;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
|
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.Bundle;
|
||||||
import org.hl7.fhir.r5.model.Meta;
|
import org.hl7.fhir.r5.model.Meta;
|
||||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||||
|
@ -68,8 +71,8 @@ public class JpaR5Config {
|
||||||
|
|
||||||
@Bean(name = JpaConfig.GRAPHQL_PROVIDER_NAME)
|
@Bean(name = JpaConfig.GRAPHQL_PROVIDER_NAME)
|
||||||
@Lazy
|
@Lazy
|
||||||
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport) {
|
public GraphQLProvider graphQLProvider(FhirContext theFhirContext, IGraphQLStorageServices theGraphqlStorageServices, IValidationSupport theValidationSupport, ISearchParamRegistry theSearchParamRegistry, IDaoRegistry theDaoRegistry) {
|
||||||
return new GraphQLProvider(theFhirContext, theValidationSupport, theGraphqlStorageServices);
|
return new GraphQLProviderWithIntrospection(theFhirContext, theValidationSupport, theGraphqlStorageServices, theSearchParamRegistry, theDaoRegistry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "mySystemDaoR5")
|
@Bean(name = "mySystemDaoR5")
|
||||||
|
|
|
@ -161,6 +161,9 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <T extends IBaseResource> List<T> fetchAllStructureDefinitions() {
|
public <T extends IBaseResource> List<T> fetchAllStructureDefinitions() {
|
||||||
|
if (!myDaoRegistry.isResourceTypeSupported("StructureDefinition")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
IBundleProvider search = myDaoRegistry.getResourceDao("StructureDefinition").search(new SearchParameterMap().setLoadSynchronousUpTo(1000));
|
IBundleProvider search = myDaoRegistry.getResourceDao("StructureDefinition").search(new SearchParameterMap().setLoadSynchronousUpTo(1000));
|
||||||
return (List<T>) search.getResources(0, 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();
|
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 {
|
public static String loadClasspath(String resource) throws IOException {
|
||||||
return new String(loadClasspathBytes(resource), Constants.CHARSET_UTF8);
|
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.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
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.param.StringParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
@ -105,6 +106,10 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
assertThat(paths.toString(), paths, contains("Observation.subject", "Observation.subject.where(resolve() is Patient)"));
|
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
|
@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.OptionalParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
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.param.TokenAndListParam;
|
||||||
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
|
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
|
||||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
import org.apache.commons.io.IOUtils;
|
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.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
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.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseReference;
|
import org.hl7.fhir.instance.model.api.IBaseReference;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
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.BeforeAll;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -47,15 +42,19 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
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_PREFIX = "{\"data\": ";
|
||||||
public static final String DATA_SUFFIX = "}";
|
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 final FhirContext ourCtx = FhirContext.forR4Cached();
|
||||||
private static int ourPort;
|
private static CloseableHttpClient ourClient;
|
||||||
private static Server ourServer;
|
private MyStorageServices myGraphQLStorageServices = new MyStorageServices();
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
private RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(ourCtx)
|
||||||
|
.registerProvider(new DummyPatientResourceProvider())
|
||||||
|
.registerProvider(new GraphQLProvider(myGraphQLStorageServices));
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void before() {
|
public void before() {
|
||||||
|
@ -65,9 +64,8 @@ public class JpaGraphQLR4ProviderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testGraphInstance() throws Exception {
|
public void testGraphInstance() throws Exception {
|
||||||
String query = "{name{family,given}}";
|
String query = "{name{family,given}}";
|
||||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||||
try {
|
|
||||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseContent);
|
ourLog.info(responseContent);
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
@ -81,9 +79,6 @@ public class JpaGraphQLR4ProviderTest {
|
||||||
" }]\n" +
|
" }]\n" +
|
||||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
||||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
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
|
@Test
|
||||||
public void testGraphInstanceWithFhirpath() throws Exception {
|
public void testGraphInstanceWithFhirpath() throws Exception {
|
||||||
String query = "{name(fhirpath:\"family.exists()\"){text,given,family}}";
|
String query = "{name(fhirpath:\"family.exists()\"){text,given,family}}";
|
||||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/Patient/123/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||||
try {
|
|
||||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseContent);
|
ourLog.info(responseContent);
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
@ -105,9 +99,6 @@ public class JpaGraphQLR4ProviderTest {
|
||||||
" }]\n" +
|
" }]\n" +
|
||||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
||||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
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
|
@Test
|
||||||
public void testGraphSystemInstance() throws Exception {
|
public void testGraphSystemInstance() throws Exception {
|
||||||
String query = "{Patient(id:123){id,name{given,family}}}";
|
String query = "{Patient(id:123){id,name{given,family}}}";
|
||||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||||
try {
|
|
||||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseContent);
|
ourLog.info(responseContent);
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
@ -133,9 +123,6 @@ public class JpaGraphQLR4ProviderTest {
|
||||||
" }\n" +
|
" }\n" +
|
||||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
||||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
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
|
@Test
|
||||||
public void testGraphSystemList() throws Exception {
|
public void testGraphSystemList() throws Exception {
|
||||||
String query = "{PatientList(name:\"pet\"){name{family,given}}}";
|
String query = "{PatientList(name:\"pet\"){name{family,given}}}";
|
||||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
|
||||||
try {
|
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseContent);
|
ourLog.info(responseContent);
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
@ -166,8 +153,6 @@ public class JpaGraphQLR4ProviderTest {
|
||||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
||||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
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
|
@Test
|
||||||
public void testGraphSystemArrayArgumentList() throws Exception {
|
public void testGraphSystemArrayArgumentList() throws Exception {
|
||||||
String query = "{PatientList(id:[\"hapi-123\",\"hapi-124\"]){id,name{family}}}";
|
String query = "{PatientList(id:[\"hapi-123\",\"hapi-124\"]){id,name{family}}}";
|
||||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
HttpGet httpGet = new HttpGet("http://localhost:" + myRestfulServerExtension.getPort() + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
|
||||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||||
try {
|
|
||||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseContent);
|
ourLog.info(responseContent);
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
@ -196,41 +180,21 @@ public class JpaGraphQLR4ProviderTest {
|
||||||
" }]\n" +
|
" }]\n" +
|
||||||
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
|
||||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
||||||
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
public static void afterClassClearContext() throws Exception {
|
public static void afterClassClearContext() throws Exception {
|
||||||
JettyUtil.closeServer(ourServer);
|
ourClient.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void beforeClass() throws Exception {
|
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);
|
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||||
builder.setConnectionManager(connectionManager);
|
builder.setConnectionManager(connectionManager);
|
||||||
ourClient = builder.build();
|
ourClient = builder.build();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
public static class DummyPatientResourceProvider implements IResourceProvider {
|
|
@ -14,8 +14,8 @@ import org.slf4j.LoggerFactory;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import static ca.uhn.fhir.jpa.provider.JpaGraphQLR4ProviderTest.DATA_PREFIX;
|
import static ca.uhn.fhir.jpa.provider.GraphQLR4ProviderTest.DATA_PREFIX;
|
||||||
import static ca.uhn.fhir.jpa.provider.JpaGraphQLR4ProviderTest.DATA_SUFFIX;
|
import static ca.uhn.fhir.jpa.provider.GraphQLR4ProviderTest.DATA_SUFFIX;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
public class GraphQLProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
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>
|
<groupId>org.postgresql</groupId>
|
||||||
<artifactId>postgresql</artifactId>
|
<artifactId>postgresql</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-jpaserver-base</artifactId>
|
<artifactId>hapi-fhir-jpaserver-base</artifactId>
|
||||||
|
@ -102,6 +103,12 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- TEST DEPS -->
|
<!-- TEST DEPS -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-servlets</artifactId>
|
<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.LoggingInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory;
|
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.TestDstu2Config;
|
||||||
import ca.uhn.fhirtest.config.TestDstu3Config;
|
import ca.uhn.fhirtest.config.TestDstu3Config;
|
||||||
import ca.uhn.fhirtest.config.TestR4Config;
|
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}");
|
loggingInterceptor.setMessageFormat("${operationType} Content-Type: ${requestHeader.content-type} - Accept: ${responseEncodingNoDefault} \"${requestHeader.accept}\" - Agent: ${requestHeader.user-agent}");
|
||||||
registerInterceptor(loggingInterceptor);
|
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.HapiJpaConfig;
|
||||||
import ca.uhn.fhir.jpa.config.JpaDstu2Config;
|
import ca.uhn.fhir.jpa.config.JpaDstu2Config;
|
||||||
import ca.uhn.fhir.jpa.config.util.HapiEntityManagerFactoryUtil;
|
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.dialect.HapiFhirPostgres94Dialect;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
||||||
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
|
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.jpa.validation.ValidationSettings;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||||
import ca.uhn.fhir.validation.IValidatorModule;
|
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.hibernate.search.engine.cfg.BackendSettings;
|
||||||
import org.hl7.fhir.dstu2.model.Subscription;
|
import org.hl7.fhir.dstu2.model.Subscription;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
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.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -44,16 +43,11 @@ import java.util.concurrent.TimeUnit;
|
||||||
@EnableTransactionManagement()
|
@EnableTransactionManagement()
|
||||||
public class TestDstu2Config {
|
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 = System.getProperty(TestR5Config.FHIR_DB_USERNAME);
|
||||||
private String myDbUsername;
|
private String myDbPassword = System.getProperty(TestR5Config.FHIR_DB_PASSWORD);
|
||||||
|
private String myFhirLuceneLocation = System.getProperty(FHIR_LUCENE_LOCATION_DSTU2);
|
||||||
@Value(TestDstu3Config.FHIR_DB_PASSWORD)
|
|
||||||
private String myDbPassword;
|
|
||||||
|
|
||||||
@Value(FHIR_LUCENE_LOCATION_DSTU2)
|
|
||||||
private String myFhirLuceneLocation;
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public PublicSecurityInterceptor securityInterceptor() {
|
public PublicSecurityInterceptor securityInterceptor() {
|
||||||
|
@ -88,7 +82,9 @@ public class TestDstu2Config {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ModelConfig modelConfig() {
|
public ModelConfig modelConfig() {
|
||||||
return daoConfig().getModelConfig();
|
ModelConfig retVal = daoConfig().getModelConfig();
|
||||||
|
retVal.setIndexIdentifierOfType(true);
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -103,7 +99,7 @@ public class TestDstu2Config {
|
||||||
public DataSource dataSource() {
|
public DataSource dataSource() {
|
||||||
BasicDataSource retVal = new BasicDataSource();
|
BasicDataSource retVal = new BasicDataSource();
|
||||||
if (CommonConfig.isLocalTestMode()) {
|
if (CommonConfig.isLocalTestMode()) {
|
||||||
retVal.setUrl("jdbc:derby:memory:fhirtest_dstu2;create=true");
|
retVal.setUrl("jdbc:h2:mem:fhirtest_dstu2");
|
||||||
} else {
|
} else {
|
||||||
retVal.setDriver(new org.postgresql.Driver());
|
retVal.setDriver(new org.postgresql.Driver());
|
||||||
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_dstu2");
|
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_dstu2");
|
||||||
|
@ -144,7 +140,7 @@ public class TestDstu2Config {
|
||||||
private Properties jpaProperties() {
|
private Properties jpaProperties() {
|
||||||
Properties extraProperties = new Properties();
|
Properties extraProperties = new Properties();
|
||||||
if (CommonConfig.isLocalTestMode()) {
|
if (CommonConfig.isLocalTestMode()) {
|
||||||
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
|
extraProperties.put("hibernate.dialect", HapiFhirH2Dialect.class.getName());
|
||||||
} else {
|
} else {
|
||||||
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
||||||
}
|
}
|
||||||
|
@ -168,6 +164,7 @@ public class TestDstu2Config {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean which validates incoming requests
|
* Bean which validates incoming requests
|
||||||
|
*
|
||||||
* @param theInstanceValidator
|
* @param theInstanceValidator
|
||||||
*/
|
*/
|
||||||
@Bean
|
@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.HapiJpaConfig;
|
||||||
import ca.uhn.fhir.jpa.config.dstu3.JpaDstu3Config;
|
import ca.uhn.fhir.jpa.config.dstu3.JpaDstu3Config;
|
||||||
import ca.uhn.fhir.jpa.config.util.HapiEntityManagerFactoryUtil;
|
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.dialect.HapiFhirPostgres94Dialect;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
||||||
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
|
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.jpa.validation.ValidationSettings;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||||
import ca.uhn.fhir.validation.IInstanceValidatorModule;
|
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.hibernate.search.engine.cfg.BackendSettings;
|
||||||
import org.hl7.fhir.dstu2.model.Subscription;
|
import org.hl7.fhir.dstu2.model.Subscription;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
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.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -48,14 +47,9 @@ public class TestDstu3Config {
|
||||||
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}";
|
public static final String FHIR_LUCENE_LOCATION_DSTU3 = "${fhir.lucene.location.dstu3}";
|
||||||
|
|
||||||
@Value(TestDstu3Config.FHIR_DB_USERNAME)
|
private String myDbUsername = System.getProperty(TestR5Config.FHIR_DB_USERNAME);
|
||||||
private String myDbUsername;
|
private String myDbPassword = System.getProperty(TestR5Config.FHIR_DB_PASSWORD);
|
||||||
|
private String myFhirLuceneLocation = System.getProperty(FHIR_LUCENE_LOCATION_DSTU3);
|
||||||
@Value(TestDstu3Config.FHIR_DB_PASSWORD)
|
|
||||||
private String myDbPassword;
|
|
||||||
|
|
||||||
@Value(FHIR_LUCENE_LOCATION_DSTU3)
|
|
||||||
private String myFhirLuceneLocation;
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public DaoConfig daoConfig() {
|
public DaoConfig daoConfig() {
|
||||||
|
@ -85,7 +79,9 @@ public class TestDstu3Config {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ModelConfig modelConfig() {
|
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() {
|
public DataSource dataSource() {
|
||||||
BasicDataSource retVal = new BasicDataSource();
|
BasicDataSource retVal = new BasicDataSource();
|
||||||
if (CommonConfig.isLocalTestMode()) {
|
if (CommonConfig.isLocalTestMode()) {
|
||||||
retVal.setUrl("jdbc:derby:memory:fhirtest_dstu3;create=true");
|
retVal.setUrl("jdbc:h2:mem:fhirtest_dstu3");
|
||||||
} else {
|
} else {
|
||||||
retVal.setDriver(new org.postgresql.Driver());
|
retVal.setDriver(new org.postgresql.Driver());
|
||||||
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_dstu3");
|
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_dstu3");
|
||||||
|
@ -147,7 +143,7 @@ public class TestDstu3Config {
|
||||||
private Properties jpaProperties() {
|
private Properties jpaProperties() {
|
||||||
Properties extraProperties = new Properties();
|
Properties extraProperties = new Properties();
|
||||||
if (CommonConfig.isLocalTestMode()) {
|
if (CommonConfig.isLocalTestMode()) {
|
||||||
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
|
extraProperties.put("hibernate.dialect", HapiFhirH2Dialect.class.getName());
|
||||||
} else {
|
} else {
|
||||||
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
||||||
}
|
}
|
||||||
|
@ -171,6 +167,7 @@ public class TestDstu3Config {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean which validates incoming requests
|
* Bean which validates incoming requests
|
||||||
|
*
|
||||||
* @param theFhirInstanceValidator
|
* @param theFhirInstanceValidator
|
||||||
*/
|
*/
|
||||||
@Bean
|
@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.HapiJpaConfig;
|
||||||
import ca.uhn.fhir.jpa.config.r4.JpaR4Config;
|
import ca.uhn.fhir.jpa.config.r4.JpaR4Config;
|
||||||
import ca.uhn.fhir.jpa.config.util.HapiEntityManagerFactoryUtil;
|
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.dialect.HapiFhirPostgres94Dialect;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
||||||
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
|
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.jpa.validation.ValidationSettings;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||||
import ca.uhn.fhir.validation.IInstanceValidatorModule;
|
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.hibernate.search.engine.cfg.BackendSettings;
|
||||||
import org.hl7.fhir.dstu2.model.Subscription;
|
import org.hl7.fhir.dstu2.model.Subscription;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
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.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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 String FHIR_LUCENE_LOCATION_R4 = "${fhir.lucene.location.r4}";
|
||||||
public static final Integer COUNT_SEARCH_RESULTS_UP_TO = 50000;
|
public static final Integer COUNT_SEARCH_RESULTS_UP_TO = 50000;
|
||||||
|
|
||||||
@Value(TestR4Config.FHIR_DB_USERNAME)
|
private String myDbUsername = System.getProperty(TestR5Config.FHIR_DB_USERNAME);
|
||||||
private String myDbUsername;
|
private String myDbPassword = System.getProperty(TestR5Config.FHIR_DB_PASSWORD);
|
||||||
|
private String myFhirLuceneLocation = System.getProperty(FHIR_LUCENE_LOCATION_R4);
|
||||||
@Value(TestR4Config.FHIR_DB_PASSWORD)
|
|
||||||
private String myDbPassword;
|
|
||||||
|
|
||||||
@Value(FHIR_LUCENE_LOCATION_R4)
|
|
||||||
private String myFhirLuceneLocation;
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public DaoConfig daoConfig() {
|
public DaoConfig daoConfig() {
|
||||||
|
@ -85,7 +79,9 @@ public class TestR4Config {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ModelConfig modelConfig() {
|
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() {
|
public DataSource dataSource() {
|
||||||
BasicDataSource retVal = new BasicDataSource();
|
BasicDataSource retVal = new BasicDataSource();
|
||||||
if (CommonConfig.isLocalTestMode()) {
|
if (CommonConfig.isLocalTestMode()) {
|
||||||
retVal.setUrl("jdbc:derby:memory:fhirtest_r4;create=true");
|
retVal.setUrl("jdbc:h2:mem:fhirtest_r4");
|
||||||
} else {
|
} else {
|
||||||
retVal.setDriver(new org.postgresql.Driver());
|
retVal.setDriver(new org.postgresql.Driver());
|
||||||
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_r4");
|
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_r4");
|
||||||
|
@ -142,7 +138,7 @@ public class TestR4Config {
|
||||||
private Properties jpaProperties() {
|
private Properties jpaProperties() {
|
||||||
Properties extraProperties = new Properties();
|
Properties extraProperties = new Properties();
|
||||||
if (CommonConfig.isLocalTestMode()) {
|
if (CommonConfig.isLocalTestMode()) {
|
||||||
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
|
extraProperties.put("hibernate.dialect", HapiFhirH2Dialect.class.getName());
|
||||||
} else {
|
} else {
|
||||||
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
||||||
}
|
}
|
||||||
|
@ -165,6 +161,7 @@ public class TestR4Config {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean which validates incoming requests
|
* Bean which validates incoming requests
|
||||||
|
*
|
||||||
* @param theFhirInstanceValidator
|
* @param theFhirInstanceValidator
|
||||||
*/
|
*/
|
||||||
@Bean
|
@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.HapiJpaConfig;
|
||||||
import ca.uhn.fhir.jpa.config.r5.JpaR5Config;
|
import ca.uhn.fhir.jpa.config.r5.JpaR5Config;
|
||||||
import ca.uhn.fhir.jpa.config.util.HapiEntityManagerFactoryUtil;
|
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.dialect.HapiFhirPostgres94Dialect;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
|
||||||
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
|
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.jpa.validation.ValidationSettings;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||||
import ca.uhn.fhir.validation.IInstanceValidatorModule;
|
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.hibernate.search.engine.cfg.BackendSettings;
|
||||||
import org.hl7.fhir.dstu2.model.Subscription;
|
import org.hl7.fhir.dstu2.model.Subscription;
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
|
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.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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_DB_PASSWORD = "${fhir.db.password}";
|
||||||
public static final String FHIR_LUCENE_LOCATION_R5 = "${fhir.lucene.location.r5}";
|
public static final String FHIR_LUCENE_LOCATION_R5 = "${fhir.lucene.location.r5}";
|
||||||
public static final Integer COUNT_SEARCH_RESULTS_UP_TO = 50000;
|
public static final Integer COUNT_SEARCH_RESULTS_UP_TO = 50000;
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(TestR5Config.class);
|
||||||
@Value(TestR5Config.FHIR_DB_USERNAME)
|
private String myDbUsername = System.getProperty(TestR5Config.FHIR_DB_USERNAME);
|
||||||
private String myDbUsername;
|
private String myDbPassword = System.getProperty(TestR5Config.FHIR_DB_PASSWORD);
|
||||||
|
private String myFhirLuceneLocation = System.getProperty(FHIR_LUCENE_LOCATION_R5);
|
||||||
@Value(TestR5Config.FHIR_DB_PASSWORD)
|
|
||||||
private String myDbPassword;
|
|
||||||
|
|
||||||
@Value(FHIR_LUCENE_LOCATION_R5)
|
|
||||||
private String myFhirLuceneLocation;
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public DaoConfig daoConfig() {
|
public DaoConfig daoConfig() {
|
||||||
|
@ -85,7 +81,9 @@ public class TestR5Config {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ModelConfig modelConfig() {
|
public ModelConfig modelConfig() {
|
||||||
return daoConfig().getModelConfig();
|
ModelConfig retVal = daoConfig().getModelConfig();
|
||||||
|
retVal.setIndexIdentifierOfType(true);
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -97,9 +95,12 @@ public class TestR5Config {
|
||||||
|
|
||||||
@Bean(name = "myPersistenceDataSourceR5")
|
@Bean(name = "myPersistenceDataSourceR5")
|
||||||
public DataSource dataSource() {
|
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();
|
BasicDataSource retVal = new BasicDataSource();
|
||||||
if (CommonConfig.isLocalTestMode()) {
|
if (CommonConfig.isLocalTestMode()) {
|
||||||
retVal.setUrl("jdbc:derby:memory:fhirtest_r5;create=true");
|
retVal.setUrl("jdbc:h2:mem:fhirtest_r5");
|
||||||
} else {
|
} else {
|
||||||
retVal.setDriver(new org.postgresql.Driver());
|
retVal.setDriver(new org.postgresql.Driver());
|
||||||
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_r5");
|
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_r5");
|
||||||
|
@ -141,7 +142,7 @@ public class TestR5Config {
|
||||||
private Properties jpaProperties() {
|
private Properties jpaProperties() {
|
||||||
Properties extraProperties = new Properties();
|
Properties extraProperties = new Properties();
|
||||||
if (CommonConfig.isLocalTestMode()) {
|
if (CommonConfig.isLocalTestMode()) {
|
||||||
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
|
extraProperties.put("hibernate.dialect", HapiFhirH2Dialect.class.getName());
|
||||||
} else {
|
} else {
|
||||||
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
extraProperties.put("hibernate.dialect", HapiFhirPostgres94Dialect.class.getName());
|
||||||
}
|
}
|
||||||
|
@ -165,6 +166,7 @@ public class TestR5Config {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean which validates incoming requests
|
* Bean which validates incoming requests
|
||||||
|
*
|
||||||
* @param theFhirInstanceValidator
|
* @param theFhirInstanceValidator
|
||||||
*/
|
*/
|
||||||
@Bean
|
@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.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
|
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
import ca.uhn.fhir.model.api.annotation.Description;
|
import ca.uhn.fhir.model.api.annotation.Description;
|
||||||
import ca.uhn.fhir.rest.annotation.GraphQL;
|
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.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Initialize;
|
import ca.uhn.fhir.rest.annotation.Initialize;
|
||||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
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.RestfulServer;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
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 ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
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.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.utilities.graphql.IGraphQLEngine;
|
import org.hl7.fhir.utilities.graphql.IGraphQLEngine;
|
||||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||||
import org.hl7.fhir.utilities.graphql.ObjectValue;
|
import org.hl7.fhir.utilities.graphql.ObjectValue;
|
||||||
|
import org.hl7.fhir.utilities.graphql.Package;
|
||||||
import org.hl7.fhir.utilities.graphql.Parser;
|
import org.hl7.fhir.utilities.graphql.Parser;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -54,9 +56,10 @@ import javax.annotation.Nullable;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class GraphQLProvider {
|
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 final IGraphQLStorageServices myStorageServices;
|
||||||
private Logger ourLog = LoggerFactory.getLogger(GraphQLProvider.class);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor which uses a default context and validation support object
|
* Constructor which uses a default context and validation support object
|
||||||
|
@ -83,21 +86,21 @@ public class GraphQLProvider {
|
||||||
IValidationSupport validationSupport = theValidationSupport;
|
IValidationSupport validationSupport = theValidationSupport;
|
||||||
validationSupport = ObjectUtils.defaultIfNull(validationSupport, new DefaultProfileValidationSupport(theFhirContext));
|
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);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case R4: {
|
case R4: {
|
||||||
IValidationSupport validationSupport = theValidationSupport;
|
IValidationSupport validationSupport = theValidationSupport;
|
||||||
validationSupport = ObjectUtils.defaultIfNull(validationSupport, new DefaultProfileValidationSupport(theFhirContext));
|
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);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case R5: {
|
case R5: {
|
||||||
IValidationSupport validationSupport = theValidationSupport;
|
IValidationSupport validationSupport = theValidationSupport;
|
||||||
validationSupport = ObjectUtils.defaultIfNull(validationSupport, new DefaultProfileValidationSupport(theFhirContext));
|
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);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case DSTU2:
|
case DSTU2:
|
||||||
|
@ -111,8 +114,8 @@ public class GraphQLProvider {
|
||||||
myStorageServices = theStorageServices;
|
myStorageServices = theStorageServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Description(value="This operation invokes a GraphQL expression for fetching an joining a graph of resources, returning them in a custom format.")
|
@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)
|
@GraphQL(type = RequestTypeEnum.GET)
|
||||||
public String processGraphQlGetRequest(ServletRequestDetails theRequestDetails, @IdParam IIdType theId, @GraphQLQueryUrl String theQueryUrl) {
|
public String processGraphQlGetRequest(ServletRequestDetails theRequestDetails, @IdParam IIdType theId, @GraphQLQueryUrl String theQueryUrl) {
|
||||||
if (theQueryUrl != null) {
|
if (theQueryUrl != null) {
|
||||||
return processGraphQLRequest(theRequestDetails, theId, theQueryUrl);
|
return processGraphQLRequest(theRequestDetails, theId, theQueryUrl);
|
||||||
|
@ -120,24 +123,31 @@ public class GraphQLProvider {
|
||||||
throw new InvalidRequestException(Msg.code(1144) + "Unable to parse empty GraphQL expression");
|
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.")
|
@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)
|
@GraphQL(type = RequestTypeEnum.POST)
|
||||||
public String processGraphQlPostRequest(ServletRequestDetails theRequestDetails, @IdParam IIdType theId, @GraphQLQueryBody String theQueryBody) {
|
public String processGraphQlPostRequest(ServletRequestDetails theServletRequestDetails, RequestDetails theRequestDetails, @IdParam IIdType theId, @GraphQLQueryBody String theQueryBody) {
|
||||||
if (theQueryBody != null) {
|
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");
|
throw new InvalidRequestException(Msg.code(1145) + "Unable to parse empty GraphQL expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String processGraphQLRequest(ServletRequestDetails theRequestDetails, IIdType theId, String theQuery) {
|
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.setAppInfo(theRequestDetails);
|
||||||
engine.setServices(myStorageServices);
|
engine.setServices(myStorageServices);
|
||||||
try {
|
engine.setGraphQL(parsedGraphQLRequest);
|
||||||
engine.setGraphQL(Parser.parse(theQuery));
|
|
||||||
} catch (Exception theE) {
|
|
||||||
throw new InvalidRequestException(Msg.code(1146) + "Unable to parse GraphQL Expression: " + theE.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
@ -167,7 +177,7 @@ public class GraphQLProvider {
|
||||||
ourLog.error("Failure during GraphQL processing", e);
|
ourLog.error("Failure during GraphQL processing", e);
|
||||||
}
|
}
|
||||||
b.append(e.getMessage());
|
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 {
|
public class LoggingInterceptorTest {
|
||||||
|
|
||||||
private static FhirContext ourCtx = FhirContext.forR4();
|
private static final FhirContext ourCtx = FhirContext.forR4Cached();
|
||||||
private static int ourPort;
|
private static int ourPort;
|
||||||
private static Server ourServer;
|
private static Server ourServer;
|
||||||
private Logger myLoggerRoot;
|
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.OptionalParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
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.RequestTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
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.TestUtil;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
import org.apache.commons.io.IOUtils;
|
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.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
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.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.HumanName;
|
import org.hl7.fhir.r4.model.HumanName;
|
||||||
import org.hl7.fhir.r4.model.IdType;
|
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.BeforeAll;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
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.containsString;
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
public class GraphQLR4RawTest {
|
public class GraphQLR4RawTest {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GraphQLR4RawTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GraphQLR4RawTest.class);
|
||||||
private static CloseableHttpClient ourClient;
|
private static CloseableHttpClient ourClient;
|
||||||
private static FhirContext ourCtx = FhirContext.forR4();
|
private static final FhirContext ourCtx = FhirContext.forR4Cached();
|
||||||
private static int ourPort;
|
|
||||||
private static Server ourServer;
|
|
||||||
private static String ourNextRetVal;
|
private static String ourNextRetVal;
|
||||||
private static IdType ourLastId;
|
private static IdType ourLastId;
|
||||||
private static String ourLastQuery;
|
private static String ourLastQuery;
|
||||||
private static int ourMethodCount;
|
private static String ourLastResourceType;
|
||||||
|
|
||||||
@AfterAll
|
@RegisterExtension
|
||||||
public static void afterClassClearContext() throws Exception {
|
private final RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(ourCtx)
|
||||||
JettyUtil.closeServer(ourServer);
|
.registerProvider(new MyPatientResourceProvider())
|
||||||
TestUtil.randomizeLocaleAndTimezone();
|
.registerProvider(new MyGraphQLProvider());
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void before() {
|
public void before() {
|
||||||
ourNextRetVal = null;
|
ourNextRetVal = null;
|
||||||
ourLastId = null;
|
ourLastId = null;
|
||||||
ourLastQuery = null;
|
ourLastQuery = null;
|
||||||
ourMethodCount = 0;
|
ourLastResourceType = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGraphInstance() throws Exception {
|
public void testGraphInstance_Get() throws Exception {
|
||||||
ourNextRetVal = "{\"foo\"}";
|
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);
|
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||||
try {
|
try {
|
||||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
@ -118,12 +89,29 @@ public class GraphQLR4RawTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGraphPostContentTypeJson() throws Exception {
|
public void testGraphInstance_Get_UnsupportedResourceType() throws Exception {
|
||||||
ourNextRetVal = "{\"foo\"}";
|
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}}\"}");
|
StringEntity entity = new StringEntity("{\"query\": \"{name{family,given}}\"}");
|
||||||
httpPost.setEntity(entity);
|
httpPost.setEntity(entity);
|
||||||
httpPost.setHeader("Accept", "application/json");
|
httpPost.setHeader("Accept", "application/json");
|
||||||
|
@ -147,10 +135,10 @@ public class GraphQLR4RawTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGraphPostContentTypeGraphql() throws Exception {
|
public void testGraphInstance_Post_ContentTypeGraphql() throws Exception {
|
||||||
ourNextRetVal = "{\"foo\"}";
|
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}}");
|
StringEntity entity = new StringEntity("{name{family,given}}");
|
||||||
httpPost.setEntity(entity);
|
httpPost.setEntity(entity);
|
||||||
httpPost.setHeader("Accept", "application/json");
|
httpPost.setHeader("Accept", "application/json");
|
||||||
|
@ -166,6 +154,7 @@ public class GraphQLR4RawTest {
|
||||||
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
|
||||||
assertEquals("Patient/123", ourLastId.getValue());
|
assertEquals("Patient/123", ourLastId.getValue());
|
||||||
assertEquals("{name{family,given}}", ourLastQuery);
|
assertEquals("{name{family,given}}", ourLastQuery);
|
||||||
|
assertEquals("Patient", ourLastResourceType);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
@ -173,31 +162,41 @@ public class GraphQLR4RawTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGraphInstanceUnknownType() throws Exception {
|
public void testGraphBase_Post_ListQuery() throws Exception {
|
||||||
ourNextRetVal = "{\"foo\"}";
|
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(httpPost);
|
||||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
|
||||||
try {
|
try {
|
||||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
ourLog.info(responseContent);
|
ourLog.info(responseContent);
|
||||||
assertEquals(404, status.getStatusLine().getStatusCode());
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
assertThat(responseContent, containsString("Unknown resource type"));
|
|
||||||
|
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 {
|
} finally {
|
||||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGraphSystem() throws Exception {
|
public void testGraphSystem() throws Exception {
|
||||||
ourNextRetVal = "{\"foo\"}";
|
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);
|
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||||
try {
|
try {
|
||||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
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 {
|
public static class MyGraphQLProvider {
|
||||||
|
|
||||||
@GraphQL(type=RequestTypeEnum.GET)
|
@GraphQL(type = RequestTypeEnum.GET)
|
||||||
public String processGet(@IdParam IdType theId, @GraphQLQueryUrl String theQuery) {
|
public String processGet(@IdParam IdType theId, @GraphQLQueryUrl String theQuery) {
|
||||||
ourMethodCount++;
|
|
||||||
ourLastId = theId;
|
ourLastId = theId;
|
||||||
ourLastQuery = theQuery;
|
ourLastQuery = theQuery;
|
||||||
return ourNextRetVal;
|
return ourNextRetVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GraphQL(type=RequestTypeEnum.POST)
|
@GraphQL(type = RequestTypeEnum.POST)
|
||||||
public String processPost(@IdParam IdType theId, @GraphQLQueryBody String theQuery) {
|
public String processPost(RequestDetails theRequestDetails, @IdParam IdType theId, @GraphQLQueryBody String theQuery) {
|
||||||
ourMethodCount++;
|
|
||||||
ourLastId = theId;
|
ourLastId = theId;
|
||||||
|
ourLastResourceType = theRequestDetails.getResourceName();
|
||||||
ourLastQuery = theQuery;
|
ourLastQuery = theQuery;
|
||||||
return ourNextRetVal;
|
return ourNextRetVal;
|
||||||
}
|
}
|
||||||
|
@ -246,13 +258,13 @@ public class GraphQLR4RawTest {
|
||||||
@Search()
|
@Search()
|
||||||
public List search(
|
public List search(
|
||||||
@OptionalParam(name = Patient.SP_IDENTIFIER) TokenAndListParam theIdentifiers) {
|
@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++) {
|
for (int i = 0; i < 200; i++) {
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
patient.addName(new HumanName().setFamily("FAMILY"));
|
patient.addName(new HumanName().setFamily("FAMILY"));
|
||||||
patient.getIdElement().setValue("Patient/" + i);
|
patient.getIdElement().setValue("Patient/" + i);
|
||||||
retVal.add((Patient) patient);
|
retVal.add(patient);
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,10 @@ package ca.uhn.fhir.util;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
|
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.Observation;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
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.Quantity;
|
||||||
import org.hl7.fhir.r4.model.Reference;
|
import org.hl7.fhir.r4.model.Reference;
|
||||||
import org.hl7.fhir.r4.model.Resource;
|
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
|
@Test
|
||||||
public void testReferences() throws EGraphQLException, EGraphEngine, IOException, FHIRException {
|
public void testReferences() throws EGraphQLException, EGraphEngine, IOException, FHIRException {
|
||||||
|
|
||||||
|
@ -128,7 +177,7 @@ public class GraphQLEngineTest {
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void beforeClass() {
|
public static void beforeClass() {
|
||||||
ourCtx = FhirContext.forR4();
|
ourCtx = FhirContext.forR4Cached();
|
||||||
ourWorkerCtx = new HapiWorkerContext(ourCtx, ourCtx.getValidationSupport());
|
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>
|
</scm>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<!--
|
|
||||||
<repository>
|
|
||||||
<id>jitpack.io</id>
|
|
||||||
<url>https://jitpack.io</url>
|
|
||||||
<snapshots>
|
|
||||||
<enabled>false</enabled>
|
|
||||||
</snapshots>
|
|
||||||
</repository>
|
|
||||||
-->
|
|
||||||
<repository>
|
<repository>
|
||||||
<id>oss-snapshot</id>
|
<id>oss-snapshot</id>
|
||||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||||
|
@ -765,7 +756,7 @@
|
||||||
|
|
||||||
<properties>
|
<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>
|
<ucum_version>1.0.3</ucum_version>
|
||||||
|
|
||||||
<surefire_jvm_args>-Dfile.encoding=UTF-8 -Xmx2048m</surefire_jvm_args>
|
<surefire_jvm_args>-Dfile.encoding=UTF-8 -Xmx2048m</surefire_jvm_args>
|
||||||
|
@ -924,6 +915,11 @@
|
||||||
<artifactId>caffeine</artifactId>
|
<artifactId>caffeine</artifactId>
|
||||||
<version>${caffeine_version}</version>
|
<version>${caffeine_version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.graphql-java</groupId>
|
||||||
|
<artifactId>graphql-java</artifactId>
|
||||||
|
<version>17.3</version>
|
||||||
|
</dependency>
|
||||||
<!-- mail start -->
|
<!-- mail start -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.simplejavamail</groupId>
|
<groupId>org.simplejavamail</groupId>
|
||||||
|
|
Loading…
Reference in New Issue