Fix GraphQL Array of Argument should be ORed (#1966)

* provide IQueryParameterOr instead of IQueryParameterType to params.add

* add tests
This commit is contained in:
Ibrohim Kholilul Islam 2020-07-08 21:38:50 +07:00 committed by GitHub
parent 1e2505e548
commit 7a44fa3eb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 160 additions and 45 deletions

View File

@ -25,15 +25,24 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.DateOrListParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.NumberOrListParam;
import ca.uhn.fhir.rest.param.NumberParam;
import ca.uhn.fhir.rest.param.QuantityOrListParam;
import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.ReferenceOrListParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.SpecialOrListParam;
import ca.uhn.fhir.rest.param.SpecialParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException;
@ -56,6 +65,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static ca.uhn.fhir.rest.api.Constants.PARAM_FILTER;
@ -111,42 +121,63 @@ public class JpaStorageServices extends BaseHapiFhirDao<IBaseResource> implement
throw new InvalidRequestException(msg);
}
for (Value nextValue : nextArgument.getValues()) {
String value = nextValue.getValue();
IQueryParameterOr<?> queryParam;
IQueryParameterType param = null;
switch (searchParam.getParamType()) {
case NUMBER:
param = new NumberParam(value);
break;
case DATE:
param = new DateParam(value);
break;
case STRING:
param = new StringParam(value);
break;
case TOKEN:
param = new TokenParam(null, value);
break;
case REFERENCE:
param = new ReferenceParam(value);
break;
case COMPOSITE:
throw new InvalidRequestException("Composite parameters are not yet supported in GraphQL");
case QUANTITY:
param = new QuantityParam(value);
break;
case SPECIAL:
param = new SpecialParam().setValue(value);
break;
case URI:
break;
case HAS:
break;
}
params.add(searchParamName, param);
switch (searchParam.getParamType()) {
case NUMBER:
NumberOrListParam numberOrListParam = new NumberOrListParam();
for (Value value: nextArgument.getValues()) {
numberOrListParam.addOr(new NumberParam(value.getValue()));
}
queryParam = numberOrListParam;
break;
case DATE:
DateOrListParam dateOrListParam = new DateOrListParam();
for (Value value: nextArgument.getValues()) {
dateOrListParam.addOr(new DateParam(value.getValue()));
}
queryParam = dateOrListParam;
break;
case STRING:
StringOrListParam stringOrListParam = new StringOrListParam();
for (Value value: nextArgument.getValues()) {
stringOrListParam.addOr(new StringParam(value.getValue()));
}
queryParam = stringOrListParam;
break;
case TOKEN:
TokenOrListParam tokenOrListParam = new TokenOrListParam();
for (Value value: nextArgument.getValues()) {
tokenOrListParam.addOr(new TokenParam(value.getValue()));
}
queryParam = tokenOrListParam;
break;
case REFERENCE:
ReferenceOrListParam referenceOrListParam = new ReferenceOrListParam();
for (Value value: nextArgument.getValues()) {
referenceOrListParam.addOr(new ReferenceParam(value.getValue()));
}
queryParam = referenceOrListParam;
break;
case QUANTITY:
QuantityOrListParam quantityOrListParam = new QuantityOrListParam();
for (Value value: nextArgument.getValues()) {
quantityOrListParam.addOr(new QuantityParam(value.getValue()));
}
queryParam = quantityOrListParam;
break;
case SPECIAL:
SpecialOrListParam specialOrListParam = new SpecialOrListParam();
for (Value value: nextArgument.getValues()) {
specialOrListParam.addOr(new SpecialParam().setValue(value.getValue()));
}
queryParam = specialOrListParam;
break;
default:
throw new InvalidRequestException(String.format("%s parameters are not yet supported in GraphQL", searchParam.getParamType()));
}
params.add(searchParamName, queryParam);
}
RequestDetails requestDetails = (RequestDetails) theAppInfo;

View File

@ -9,6 +9,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
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.r4.model.Patient;
import org.hl7.fhir.utilities.graphql.Argument;
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
import org.hl7.fhir.utilities.graphql.StringValue;
@ -22,6 +23,7 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -94,4 +96,29 @@ public class JpaStorageServicesTest extends BaseJpaR4Test {
assertEquals("Unknown GraphQL argument \"test\". Value GraphQL argument for this type are: [_id, _language, actor, appointment_type, based_on, date, identifier, location, part_status, patient, practitioner, reason_code, reason_reference, service_category, service_type, slot, specialty, status, supporting_info]", e.getMessage());
}
}
private void createSomePatientWithId(String id) {
Patient somePatient = new Patient();
somePatient.setId(id);
myPatientDao.update(somePatient);
}
@Test
public void testListResourceGraphqlArrayOfArgument() {
createSomePatientWithId("hapi-123");
createSomePatientWithId("hapi-124");
Argument argument = new Argument();
argument.setName("_id");
argument.addValue(new StringValue("hapi-123"));
argument.addValue(new StringValue("hapi-124"));
List<IBaseResource> result = new ArrayList<>();
mySvc.listResources(mySrd, "Patient", Collections.singletonList(argument), result);
assertFalse(result.isEmpty());
List<String> expectedId = Arrays.asList("hapi-123", "hapi-124");
assertTrue(result.stream().allMatch((it) -> expectedId.contains(it.getIdElement().getIdPart())));
}
}

View File

@ -31,6 +31,7 @@ import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.utilities.graphql.Argument;
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
import org.hl7.fhir.utilities.graphql.Value;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@ -38,8 +39,11 @@ import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.startsWith;
@ -158,7 +162,38 @@ public class JpaGraphQLR4ProviderTest {
" }]\n" +
" },{\n" +
" \"name\":[{\n" +
" \"given\":[\"GivenOnlyB1\",\"GivenOnlyB2\"]\n" +
" \"given\":[\"pet\",\"GivenOnlyB1\",\"GivenOnlyB2\"]\n" +
" }]\n" +
" }]\n" +
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
assertThat(status.getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue(), startsWith("application/json"));
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
@Test
public void testGraphSystemArrayArgumentList() throws Exception {
String query = "{PatientList(id:[\"hapi-123\",\"hapi-124\"]){id,name{family}}}";
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/$graphql?query=" + UrlUtil.escapeUrlParam(query));
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals(TestUtil.stripWhitespace(DATA_PREFIX + "{\n" +
" \"PatientList\":[{\n" +
" \"id\":\"Patient/hapi-123/_history/2\",\n" +
" \"name\":[{\n" +
" \"family\":\"FAMILY 123\"\n" +
" }]\n" +
" },{\n" +
" \"id\":\"Patient/hapi-124/_history/1\",\n" +
" \"name\":[{\n" +
" \"family\":\"FAMILY 124\"\n" +
" }]\n" +
" }]\n" +
"}" + DATA_SUFFIX), TestUtil.stripWhitespace(responseContent));
@ -230,24 +265,46 @@ public class JpaGraphQLR4ProviderTest {
ourLog.info("listResources of {} - {}", theType, theSearchParams);
if (theSearchParams.size() == 1) {
String name = theSearchParams.get(0).getName();
if ("name".equals(name)) {
Patient p = new Patient();
p.addName()
.setFamily(theSearchParams.get(0).getValues().get(0).toString())
Argument argument = theSearchParams.get(0);
String name = argument.getName();
List<String> value = argument.getValues().stream()
.map((it) -> it.getValue())
.collect(Collectors.toList());
if ("name".equals(name) && "pet".equals(value.get(0))) {
Patient patient1 = new Patient();
patient1.addName()
.setFamily("pet")
.addGiven("GIVEN1")
.addGiven("GIVEN2");
p.addName()
patient1.addName()
.addGiven("GivenOnly1")
.addGiven("GivenOnly2");
theMatches.add(p);
p = new Patient();
p.addName()
Patient patient2 = new Patient();
patient2.addName()
.addGiven("pet")
.addGiven("GivenOnlyB1")
.addGiven("GivenOnlyB2");
theMatches.add(p);
theMatches.add(patient1);
theMatches.add(patient2);
}
if ("id".equals(name) && Arrays.asList("hapi-123", "hapi-124").containsAll(value)) {
Patient patient1 = new Patient();
patient1.setId("Patient/hapi-123/_history/2");
patient1.addName()
.setFamily("FAMILY 123");
Patient patient2 = new Patient();
patient2.setId("Patient/hapi-124/_history/1");
patient2.addName()
.setFamily("FAMILY 124");
theMatches.add(patient1);
theMatches.add(patient2);
}
}
}