Fix GraphQL Error (#1791)
* add debug log * add debug log to value iteration * fix _filter issue on /$graphql, fix dash and underscore issue on /$graphql, and give helpful error message on wrong argument. * remove debug logging * implement JpaStorageServicesTest
This commit is contained in:
parent
c716216b34
commit
3225075f9e
|
@ -138,5 +138,7 @@ ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.expansionTooLarge=Expansion of ValueSet
|
||||||
|
|
||||||
ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils.failedToApplyPatch=Failed to apply JSON patch to {0}: {1}
|
ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils.failedToApplyPatch=Failed to apply JSON patch to {0}: {1}
|
||||||
|
|
||||||
|
ca.uhn.fhir.jpa.graphql.JpaStorageServices.invalidGraphqlArgument=Unknown GraphQL argument "{0}". Value GraphQL argument for this type are: {1}
|
||||||
|
|
||||||
ca.uhn.fhir.jpa.dao.predicate.PredicateBuilderReference.invalidTargetTypeForChain=Resource type "{0}" is not a valid target type for reference search parameter: {1}
|
ca.uhn.fhir.jpa.dao.predicate.PredicateBuilderReference.invalidTargetTypeForChain=Resource type "{0}" is not a valid target type for reference search parameter: {1}
|
||||||
ca.uhn.fhir.jpa.dao.predicate.PredicateBuilderReference.invalidResourceType=Invalid/unsupported resource type: "{0}"
|
ca.uhn.fhir.jpa.dao.predicate.PredicateBuilderReference.invalidResourceType=Invalid/unsupported resource type: "{0}"
|
||||||
|
|
|
@ -45,21 +45,42 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.utilities.graphql.Argument;
|
import org.hl7.fhir.utilities.graphql.Argument;
|
||||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||||
import org.hl7.fhir.utilities.graphql.Value;
|
import org.hl7.fhir.utilities.graphql.Value;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static ca.uhn.fhir.rest.api.Constants.PARAM_FILTER;
|
||||||
|
|
||||||
public class JpaStorageServices extends BaseHapiFhirDao<IBaseResource> implements IGraphQLStorageServices {
|
public class JpaStorageServices extends BaseHapiFhirDao<IBaseResource> implements IGraphQLStorageServices {
|
||||||
|
|
||||||
private static final int MAX_SEARCH_SIZE = 500;
|
private static final int MAX_SEARCH_SIZE = 500;
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(JpaStorageServices.class);
|
||||||
|
|
||||||
private IFhirResourceDao<? extends IBaseResource> getDao(String theResourceType) {
|
private IFhirResourceDao<? extends IBaseResource> getDao(String theResourceType) {
|
||||||
RuntimeResourceDefinition typeDef = getContext().getResourceDefinition(theResourceType);
|
RuntimeResourceDefinition typeDef = getContext().getResourceDefinition(theResourceType);
|
||||||
return myDaoRegistry.getResourceDaoOrNull(typeDef.getImplementingClass());
|
return myDaoRegistry.getResourceDaoOrNull(typeDef.getImplementingClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String graphqlArgumentToSearchParam(String name) {
|
||||||
|
if (name.startsWith("_")) {
|
||||||
|
return name;
|
||||||
|
} else {
|
||||||
|
return name.replaceAll("_", "-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String searchParamToGraphqlArgument(String name) {
|
||||||
|
return name.replaceAll("-", "_");
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.NEVER)
|
@Transactional(propagation = Propagation.NEVER)
|
||||||
@Override
|
@Override
|
||||||
public void listResources(Object theAppInfo, String theType, List<Argument> theSearchParams, List<IBaseResource> theMatches) throws FHIRException {
|
public void listResources(Object theAppInfo, String theType, List<Argument> theSearchParams, List<IBaseResource> theMatches) throws FHIRException {
|
||||||
|
@ -70,9 +91,25 @@ public class JpaStorageServices extends BaseHapiFhirDao<IBaseResource> implement
|
||||||
SearchParameterMap params = new SearchParameterMap();
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
params.setLoadSynchronousUpTo(MAX_SEARCH_SIZE);
|
params.setLoadSynchronousUpTo(MAX_SEARCH_SIZE);
|
||||||
|
|
||||||
|
Map<String, RuntimeSearchParam> searchParams = mySearchParamRegistry.getActiveSearchParams(typeDef.getName());
|
||||||
|
|
||||||
for (Argument nextArgument : theSearchParams) {
|
for (Argument nextArgument : theSearchParams) {
|
||||||
|
|
||||||
RuntimeSearchParam searchParam = mySearchParamRegistry.getSearchParamByName(typeDef, nextArgument.getName());
|
if (nextArgument.getName().equals(PARAM_FILTER)) {
|
||||||
|
String value = nextArgument.getValues().get(0).getValue();
|
||||||
|
params.add(PARAM_FILTER, new StringParam(value));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String searchParamName = graphqlArgumentToSearchParam(nextArgument.getName());
|
||||||
|
RuntimeSearchParam searchParam = searchParams.get(searchParamName);
|
||||||
|
if (searchParam == null) {
|
||||||
|
Set<String> graphqlArguments = searchParams.keySet().stream()
|
||||||
|
.map(this::searchParamToGraphqlArgument)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
String msg = getContext().getLocalizer().getMessageSanitized(JpaStorageServices.class, "invalidGraphqlArgument", nextArgument.getName(), new TreeSet<>(graphqlArguments));
|
||||||
|
throw new InvalidRequestException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
for (Value nextValue : nextArgument.getValues()) {
|
for (Value nextValue : nextArgument.getValues()) {
|
||||||
String value = nextValue.getValue();
|
String value = nextValue.getValue();
|
||||||
|
@ -108,7 +145,7 @@ public class JpaStorageServices extends BaseHapiFhirDao<IBaseResource> implement
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
params.add(nextArgument.getName(), param);
|
params.add(searchParamName, param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
package ca.uhn.fhir.jpa.graphql;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.config.TestR4Config;
|
||||||
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
|
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.hl7.fhir.r4.model.Appointment;
|
||||||
|
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||||
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
|
import org.hl7.fhir.utilities.graphql.Argument;
|
||||||
|
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||||
|
import org.hl7.fhir.utilities.graphql.StringValue;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@ContextConfiguration(classes = {TestR4Config.class})
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@DirtiesContext
|
||||||
|
public class JpaStorageServicesTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() {
|
||||||
|
myDaoConfig.setFilterParameterEnabled(new DaoConfig().isFilterParameterEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
myDaoConfig.setFilterParameterEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IGraphQLStorageServices mySvc;
|
||||||
|
|
||||||
|
private String createSomeAppointment() {
|
||||||
|
CodeableConcept someCodeableConcept = new CodeableConcept(new Coding("TEST_SYSTEM", "TEST_CODE", "TEST_DISPLAY"));
|
||||||
|
Appointment someAppointment = new Appointment();
|
||||||
|
someAppointment.setAppointmentType(someCodeableConcept);
|
||||||
|
return myAppointmentDao.create(someAppointment).getId().getIdPart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListResourcesGraphqlArgumentConversion() {
|
||||||
|
String appointmentId = createSomeAppointment();
|
||||||
|
|
||||||
|
Argument argument = new Argument("appointment_type", new StringValue("TEST_CODE"));
|
||||||
|
|
||||||
|
List<IBaseResource> result = new ArrayList<>();
|
||||||
|
mySvc.listResources(mySrd, "Appointment", Collections.singletonList(argument), result);
|
||||||
|
|
||||||
|
Assert.assertFalse(result.isEmpty());
|
||||||
|
Assert.assertTrue(result.stream().anyMatch((it) -> it.getIdElement().getIdPart().equals(appointmentId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListResourceGraphqlFilterArgument() {
|
||||||
|
String appointmentId = createSomeAppointment();
|
||||||
|
|
||||||
|
Argument argument = new Argument("_filter", new StringValue("appointment-type eq TEST_CODE"));
|
||||||
|
|
||||||
|
List<IBaseResource> result = new ArrayList<>();
|
||||||
|
mySvc.listResources(mySrd, "Appointment", Collections.singletonList(argument), result);
|
||||||
|
|
||||||
|
Assert.assertFalse(result.isEmpty());
|
||||||
|
Assert.assertTrue(result.stream().anyMatch((it) -> it.getIdElement().getIdPart().equals(appointmentId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidRequestException.class)
|
||||||
|
public void testListResourceGraphqlInvalidException() {
|
||||||
|
Argument argument = new Argument("test", new StringValue("some test value"));
|
||||||
|
|
||||||
|
List<IBaseResource> result = new ArrayList<>();
|
||||||
|
mySvc.listResources(mySrd, "Appointment", Collections.singletonList(argument), result);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue