Add support for JPA searches with _tag:not=foo
This commit is contained in:
parent
ad34e38dee
commit
b81a343f5d
|
@ -28,6 +28,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -795,14 +796,9 @@ public class SearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
|
||||||
Root<ResourceTag> from = cq.from(ResourceTag.class);
|
|
||||||
|
|
||||||
List<Predicate> andPredicates = new ArrayList<Predicate>();
|
|
||||||
andPredicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
|
||||||
|
|
||||||
List<Predicate> orPredicates = new ArrayList<Predicate>();
|
|
||||||
boolean paramInverted = false;
|
boolean paramInverted = false;
|
||||||
|
List<Pair<String, String>> tokens = Lists.newArrayList();
|
||||||
for (IQueryParameterType nextOrParams : nextAndParams) {
|
for (IQueryParameterType nextOrParams : nextAndParams) {
|
||||||
String code;
|
String code;
|
||||||
String system;
|
String system;
|
||||||
|
@ -818,57 +814,66 @@ public class SearchBuilder {
|
||||||
code = nextParam.getValue();
|
code = nextParam.getValue();
|
||||||
system = null;
|
system = null;
|
||||||
}
|
}
|
||||||
From<ResourceTag, TagDefinition> defJoin = from.join("myTag");
|
|
||||||
Predicate typePrediate = builder.equal(defJoin.get("myTagType"), tagType);
|
if (isNotBlank(code)) {
|
||||||
Predicate codePrediate = builder.equal(defJoin.get("myCode"), code);
|
tokens.add(Pair.of(system, code));
|
||||||
if (isBlank(code)) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (isNotBlank(system)) {
|
|
||||||
Predicate systemPrediate = builder.equal(defJoin.get("mySystem"), system);
|
|
||||||
orPredicates.add(builder.and(typePrediate, systemPrediate, codePrediate));
|
|
||||||
} else {
|
|
||||||
orPredicates.add(builder.and(typePrediate, codePrediate));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
if (tokens.isEmpty()) {
|
||||||
if (orPredicates.isEmpty() == false) {
|
|
||||||
Predicate tagOptions = builder.or(toArray(orPredicates));
|
|
||||||
andPredicates.add(tagOptions);
|
|
||||||
} else {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
From<?, ResourceTable> defJoin;
|
|
||||||
if (paramInverted) {
|
if (paramInverted) {
|
||||||
Subquery<Long> subQ = cq.subquery(Long.class);
|
ourLog.debug("Searching for _tag:not");
|
||||||
Root<ResourceTag> subQfrom = cq.from(ResourceTag.class);
|
|
||||||
subQ.select(subQfrom.get("myResourceId").as(Long.class));
|
|
||||||
subQ.where(builder.and(toArray(andPredicates)));
|
|
||||||
|
|
||||||
|
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||||
Root<ResourceTable> newFrom = cq.from(ResourceTable.class);
|
Root<ResourceTable> newFrom = cq.from(ResourceTable.class);
|
||||||
cq.select(newFrom.get("myId").as(Long.class)).where(builder.not(builder.in(newFrom.get("myId")).value(subQ)));
|
|
||||||
|
|
||||||
|
Subquery<Long> subQ = cq.subquery(Long.class);
|
||||||
|
Root<ResourceTag> subQfrom = subQ.from(ResourceTag.class);
|
||||||
|
subQ.select(subQfrom.get("myResourceId").as(Long.class));
|
||||||
|
|
||||||
|
cq.select(newFrom.get("myId").as(Long.class));
|
||||||
|
|
||||||
|
List<Predicate> andPredicates = new ArrayList<Predicate>();
|
||||||
andPredicates = new ArrayList<Predicate>();
|
andPredicates = new ArrayList<Predicate>();
|
||||||
andPredicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
andPredicates.add(builder.equal(newFrom.get("myResourceType"), myResourceName));
|
||||||
defJoin = newFrom;
|
andPredicates.add(builder.not(builder.in(newFrom.get("myId")).value(subQ)));
|
||||||
|
|
||||||
|
Subquery<Long> defJoin = subQ.subquery(Long.class);
|
||||||
|
Root<TagDefinition> defJoinFrom = defJoin.from(TagDefinition.class);
|
||||||
|
defJoin.select(defJoinFrom.get("myId").as(Long.class));
|
||||||
|
|
||||||
|
subQ.where(subQfrom.get("myTagId").as(Long.class).in(defJoin));
|
||||||
|
|
||||||
|
List<Predicate> orPredicates = createPredicateTagList(defJoinFrom, builder, tagType, tokens);
|
||||||
|
defJoin.where(toArray(orPredicates));
|
||||||
|
|
||||||
|
cq.where(toArray(andPredicates));
|
||||||
|
|
||||||
TypedQuery<Long> q = myEntityManager.createQuery(cq);
|
TypedQuery<Long> q = myEntityManager.createQuery(cq);
|
||||||
Set<Long> pids = new HashSet<Long>(q.getResultList());
|
Set<Long> pids = new HashSet<Long>(q.getResultList());
|
||||||
doSetPids(pids);
|
doSetPids(pids);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
defJoin = from.join("myResource");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Predicate notDeletedPredicatePrediate = builder.isNull(defJoin.get("myDeleted"));
|
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||||
|
Root<ResourceTag> from = cq.from(ResourceTag.class);
|
||||||
|
List<Predicate> andPredicates = new ArrayList<Predicate>();
|
||||||
|
andPredicates.add(builder.equal(from.get("myResourceType"), myResourceName));
|
||||||
|
From<ResourceTag, TagDefinition> defJoin = from.join("myTag");
|
||||||
|
|
||||||
|
Join<?, ResourceTable> defJoin2 = from.join("myResource");
|
||||||
|
|
||||||
|
Predicate notDeletedPredicatePrediate = builder.isNull(defJoin2.get("myDeleted"));
|
||||||
andPredicates.add(notDeletedPredicatePrediate);
|
andPredicates.add(notDeletedPredicatePrediate);
|
||||||
|
|
||||||
|
List<Predicate> orPredicates = createPredicateTagList(defJoin, builder, tagType, tokens);
|
||||||
|
andPredicates.add(builder.or(toArray(orPredicates)));
|
||||||
|
|
||||||
if (theLastUpdated != null) {
|
if (theLastUpdated != null) {
|
||||||
andPredicates.addAll(createLastUpdatedPredicates(theLastUpdated, builder, defJoin));
|
andPredicates.addAll(createLastUpdatedPredicates(theLastUpdated, builder, defJoin2));
|
||||||
}
|
}
|
||||||
|
|
||||||
createPredicateResourceId(builder, cq, andPredicates, from.get("myResourceId").as(Long.class));
|
createPredicateResourceId(builder, cq, andPredicates, from.get("myResourceId").as(Long.class));
|
||||||
|
@ -884,6 +889,22 @@ public class SearchBuilder {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Predicate> createPredicateTagList(Path<TagDefinition> theDefJoin, CriteriaBuilder theBuilder, TagTypeEnum theTagType, List<Pair<String, String>> theTokens) {
|
||||||
|
Predicate typePrediate = theBuilder.equal(theDefJoin.get("myTagType"), theTagType);
|
||||||
|
|
||||||
|
List<Predicate> orPredicates = Lists.newArrayList();
|
||||||
|
for (Pair<String, String> next : theTokens) {
|
||||||
|
Predicate codePrediate = theBuilder.equal(theDefJoin.get("myCode"), next.getRight());
|
||||||
|
if (isNotBlank(next.getLeft())) {
|
||||||
|
Predicate systemPrediate = theBuilder.equal(theDefJoin.get("mySystem"), next.getLeft());
|
||||||
|
orPredicates.add(theBuilder.and(typePrediate, systemPrediate, codePrediate));
|
||||||
|
} else {
|
||||||
|
orPredicates.add(theBuilder.and(typePrediate, codePrediate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return orPredicates;
|
||||||
|
}
|
||||||
|
|
||||||
private void addPredicateToken(String theParamName, List<? extends IQueryParameterType> theList) {
|
private void addPredicateToken(String theParamName, List<? extends IQueryParameterType> theList) {
|
||||||
|
|
||||||
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
|
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
|
||||||
|
|
|
@ -2117,6 +2117,20 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||||
assertThat(patients, containsInAnyOrder(tag2id));
|
assertThat(patients, containsInAnyOrder(tag2id));
|
||||||
assertThat(patients, not(containsInAnyOrder(tag1id)));
|
assertThat(patients, not(containsInAnyOrder(tag1id)));
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
// Non existant tag
|
||||||
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
params.add("_tag", new TokenParam("urn:taglist", methodName + "FOO").setModifier(TokenParamModifier.NOT));
|
||||||
|
List<IIdType> patients = toUnqualifiedVersionlessIds(myOrganizationDao.search(params));
|
||||||
|
assertThat(patients, containsInAnyOrder(tag1id, tag2id));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Common tag
|
||||||
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
params.add("_tag", new TokenParam("urn:taglist", methodName + "1b").setModifier(TokenParamModifier.NOT));
|
||||||
|
List<IIdType> patients = toUnqualifiedVersionlessIds(myOrganizationDao.search(params));
|
||||||
|
assertThat(patients, empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -398,6 +398,11 @@
|
||||||
Thanks to GitHub user @ipropper for reporting and providing
|
Thanks to GitHub user @ipropper for reporting and providing
|
||||||
a test case!
|
a test case!
|
||||||
</action>
|
</action>
|
||||||
|
<action type="add">
|
||||||
|
JPA server now supports searching for <![CDATA[<code>_tag:not=[tag]</code>]]>
|
||||||
|
which enables finding resources that to not have a given tag/profile/security tag.
|
||||||
|
Thanks to Lars Kristian Roland for the suggestion!
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="1.4" date="2016-02-04">
|
<release version="1.4" date="2016-02-04">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
|
Loading…
Reference in New Issue