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.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.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.IGraphQLStorageServices;
|
||||
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.Transactional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
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 {
|
||||
|
||||
private static final int MAX_SEARCH_SIZE = 500;
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(JpaStorageServices.class);
|
||||
|
||||
private IFhirResourceDao<? extends IBaseResource> getDao(String theResourceType) {
|
||||
RuntimeResourceDefinition typeDef = getContext().getResourceDefinition(theResourceType);
|
||||
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)
|
||||
@Override
|
||||
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();
|
||||
params.setLoadSynchronousUpTo(MAX_SEARCH_SIZE);
|
||||
|
||||
Map<String, RuntimeSearchParam> searchParams = mySearchParamRegistry.getActiveSearchParams(typeDef.getName());
|
||||
|
||||
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()) {
|
||||
String value = nextValue.getValue();
|
||||
|
@ -108,7 +145,7 @@ public class JpaStorageServices extends BaseHapiFhirDao<IBaseResource> implement
|
|||
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