Skip to content

Commit

Permalink
Initial pass at some of the sorting work
Browse files Browse the repository at this point in the history
  • Loading branch information
ibacher committed Oct 8, 2024
1 parent c76a513 commit f9adbcf
Show file tree
Hide file tree
Showing 17 changed files with 250 additions and 155 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import javax.annotation.Nonnull;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;

import java.util.List;
Expand Down Expand Up @@ -92,7 +93,7 @@ protected <T, U> Optional<Predicate> handleLastUpdated(OpenmrsFhirCriteriaContex
}

@Override
protected <V, U> String paramToProp(OpenmrsFhirCriteriaContext<V, U> criteriaContext, @NonNull String param) {
protected <V, U> Path<?> paramToProp(OpenmrsFhirCriteriaContext<V, U> criteriaContext, @NonNull String param) {
return super.paramToProp(criteriaContext, param);
}
}
4 changes: 2 additions & 2 deletions api/src/main/java/org/openmrs/module/fhir2/FhirConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ private FhirConstants() {
public static final String GLOBAL_PROPERTY_MODERATE = "allergy.concept.severity.moderate";

public static final String GLOBAL_PROPERTY_OTHER = "allergy.concept.severity.other";

public static final String GLOBAL_PROPERTY_DEFAULT_CONCEPT_MAP_TYPE = "concept.defaultConceptMapType";

public static final String GLOBAL_PROPERTY_URI_PREFIX = "fhir2.uriPrefix";

public static final String ENCOUNTER_REFERENCE_SEARCH_HANDLER = "encounter.reference.search.handler";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import javax.persistence.criteria.From;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

Expand Down Expand Up @@ -245,7 +246,13 @@ protected <T extends IQueryParameterOr<U>, U extends IQueryParameterType> Option
return Optional.empty();
}

return Optional.of(criteriaBuilder.and((toCriteriaArray(handleAndListParam(andListParam).map(handler)))));
Predicate[] predicates = toCriteriaArray(handleAndListParam(andListParam).map(handler));

if (predicates.length == 0) {
return Optional.empty();
}

return Optional.of(criteriaBuilder.and(predicates));
}

protected <T extends IQueryParameterOr<U>, U extends IQueryParameterType> Optional<Predicate> handleAndListParamAsStream(
Expand All @@ -255,8 +262,14 @@ protected <T extends IQueryParameterOr<U>, U extends IQueryParameterType> Option
return Optional.empty();
}

return Optional.of(criteriaBuilder.and((toCriteriaArray(handleAndListParam(andListParam)
.map(orListParam -> handleOrListParamAsStream(criteriaBuilder, orListParam, handler))))));
Predicate[] predicates = toCriteriaArray(handleAndListParam(andListParam)
.map(orListParam -> handleOrListParamAsStream(criteriaBuilder, orListParam, handler)));

if (predicates.length == 0) {
return Optional.empty();
}

return Optional.of(criteriaBuilder.and(predicates));
}

/**
Expand All @@ -274,7 +287,13 @@ protected <T extends IQueryParameterType> Optional<Predicate> handleOrListParam(
return Optional.empty();
}

return Optional.of(criteriaBuilder.or(toCriteriaArray(handleOrListParam(orListParam).map(handler))));
Predicate[] predicates = toCriteriaArray(handleOrListParam(orListParam).map(handler));

if (predicates.length == 0) {
return Optional.empty();
}

return Optional.of(criteriaBuilder.or(predicates));
}

protected <T extends IQueryParameterType> Optional<Predicate> handleOrListParamAsStream(CriteriaBuilder criteriaBuilder,
Expand All @@ -283,7 +302,13 @@ protected <T extends IQueryParameterType> Optional<Predicate> handleOrListParamA
return Optional.empty();
}

return Optional.of(criteriaBuilder.or(toCriteriaArray(handleOrListParam(orListParam).flatMap(handler))));
Predicate[] predicates = toCriteriaArray(handleOrListParam(orListParam).flatMap(handler));

if (predicates.length == 0) {
return Optional.empty();
}

return Optional.of(criteriaBuilder.or(predicates));
}

/**
Expand Down Expand Up @@ -710,10 +735,13 @@ protected <T, U> Optional<Predicate> handleCodeableConcept(OpenmrsFhirCriteriaCo

return handleAndListParamBySystem(criteriaContext.getCriteriaBuilder(), concepts, (system, tokens) -> {
if (system.isEmpty()) {

Predicate inConceptId = criteriaContext.getCriteriaBuilder().in(conceptAlias.get("conceptId")).value(criteriaContext.getCriteriaBuilder().literal(tokensToParams(tokens).map(NumberUtils::toInt).collect(Collectors.toList())));
Predicate inUuid = criteriaContext.getCriteriaBuilder().in(conceptAlias.get("uuid")).value(criteriaContext.getCriteriaBuilder().literal(tokensToList(tokens)));


Predicate inConceptId = criteriaContext.getCriteriaBuilder().in(conceptAlias.get("conceptId"))
.value(criteriaContext.getCriteriaBuilder()
.literal(tokensToParams(tokens).map(NumberUtils::toInt).collect(Collectors.toList())));
Predicate inUuid = criteriaContext.getCriteriaBuilder().in(conceptAlias.get("uuid"))
.value(criteriaContext.getCriteriaBuilder().literal(tokensToList(tokens)));

return Optional.of(criteriaContext.getCriteriaBuilder().or(inConceptId, inUuid));
} else {
Join<?, ?> conceptMapAliasJoin = criteriaContext.addJoin(conceptAlias, "conceptMappings", conceptMapAlias);
Expand Down Expand Up @@ -891,7 +919,7 @@ protected <T, U> Optional<Predicate> handleMedicationReference(OpenmrsFhirCriter
}

protected <T, U> Optional<Predicate> handleMedicationRequestReference(OpenmrsFhirCriteriaContext<T, U> criteriaContext,
@Nonnull From<?,?> drugOrderAlias, ReferenceAndListParam drugOrderReference) {
@Nonnull From<?, ?> drugOrderAlias, ReferenceAndListParam drugOrderReference) {
if (drugOrderReference == null) {
return Optional.empty();
}
Expand All @@ -914,16 +942,16 @@ protected <T, U> void handleSort(OpenmrsFhirCriteriaContext<T, U> criteriaContex
handleSort(criteriaContext, sort, this::paramToProps).ifPresent(l -> l.forEach(criteriaContext::addOrder));
}

protected <T, U> Optional<List<javax.persistence.criteria.Order>> handleSort(
OpenmrsFhirCriteriaContext<T, U> criteriaContext, SortSpec sort,
BiFunction<OpenmrsFhirCriteriaContext<T, U>, SortState, Collection<javax.persistence.criteria.Order>> paramToProp) {
List<javax.persistence.criteria.Order> orderings = new ArrayList<>();
protected <T, U> Optional<List<Order>> handleSort(OpenmrsFhirCriteriaContext<T, U> criteriaContext, SortSpec sort,
BiFunction<OpenmrsFhirCriteriaContext<T, U>, SortState<T, U>, Collection<javax.persistence.criteria.Order>> paramToProp) {
List<Order> orderings = new ArrayList<>();
SortSpec sortSpec = sort;
while (sortSpec != null) {
SortState state = SortState.builder().context(criteriaContext).sortOrder(sortSpec.getOrder())
SortState<T, U> state = SortState.<T, U> builder().context(criteriaContext).sortOrder(sortSpec.getOrder())
.parameter(sortSpec.getParamName().toLowerCase()).build();

Collection<javax.persistence.criteria.Order> orders = paramToProp.apply(criteriaContext, state);
Collection<Order> orders = paramToProp.apply(criteriaContext, state);
if (orders != null) {
orderings.addAll(orders);
}
Expand Down Expand Up @@ -1029,18 +1057,15 @@ protected TokenAndListParam convertStringStatusToBoolean(TokenAndListParam statu
* @param sortState a {@link SortState} object describing the current sort state
* @return the corresponding ordering(s) needed for this property
*/
protected <T, U> Collection<Order> paramToProps(OpenmrsFhirCriteriaContext<T, U> criteriaContext,
@Nonnull SortState sortState) {
Collection<String> prop = paramToProps(criteriaContext, sortState.getParameter());
protected <T, U> Collection<Order> paramToProps(@Nonnull OpenmrsFhirCriteriaContext<T, U> criteriaContext,
@Nonnull SortState<T, U> sortState) {
Collection<Path<?>> prop = paramToProps(criteriaContext, sortState.getParameter());
if (prop != null) {
switch (sortState.getSortOrder()) {
case ASC:
return prop.stream().map(s -> criteriaContext.getCriteriaBuilder().asc(criteriaContext.getRoot().get(s)))
.collect(Collectors.toList());
return prop.stream().map(p -> criteriaContext.getCriteriaBuilder().asc(p)).collect(Collectors.toList());
case DESC:
return prop.stream()
.map(s -> criteriaContext.getCriteriaBuilder().desc(criteriaContext.getRoot().get(s)))
.collect(Collectors.toList());
return prop.stream().map(p -> criteriaContext.getCriteriaBuilder().desc(p)).collect(Collectors.toList());
}
}

Expand All @@ -1054,9 +1079,9 @@ protected <T, U> Collection<Order> paramToProps(OpenmrsFhirCriteriaContext<T, U>
* @param param the FHIR parameter to map
* @return the name of the corresponding property from the current query
*/
protected <T, U> Collection<String> paramToProps(OpenmrsFhirCriteriaContext<T, U> criteriaContext,
protected <T, U> Collection<Path<?>> paramToProps(@Nonnull OpenmrsFhirCriteriaContext<T, U> criteriaContext,
@Nonnull String param) {
String prop = paramToProp(criteriaContext, param);
Path<?> prop = paramToProp(criteriaContext, param);

if (prop != null) {
return Collections.singleton(prop);
Expand All @@ -1072,7 +1097,7 @@ protected <T, U> Collection<String> paramToProps(OpenmrsFhirCriteriaContext<T, U
* @param param the FHIR parameter to map
* @return the name of the corresponding property from the current query
*/
protected <T, U> String paramToProp(OpenmrsFhirCriteriaContext<T, U> criteriaContext, @Nonnull String param) {
protected <T, U> Path<?> paramToProp(OpenmrsFhirCriteriaContext<T, U> criteriaContext, @Nonnull String param) {
return null;
}

Expand Down Expand Up @@ -1126,15 +1151,15 @@ protected <T extends IQueryParameterType> Stream<T> handleOrListParam(IQueryPara

@SafeVarargs
@SuppressWarnings("unused")
protected final Predicate[] toCriteriaArray(Optional<? extends Predicate>... predicate) {
protected final @Nonnull Predicate[] toCriteriaArray(@Nonnull Optional<? extends Predicate>... predicate) {
return toCriteriaArray(Arrays.stream(predicate));
}

protected Predicate[] toCriteriaArray(Collection<Optional<? extends Predicate>> collection) {
protected @Nonnull Predicate[] toCriteriaArray(@Nonnull Collection<Optional<? extends Predicate>> collection) {
return toCriteriaArray(collection.stream());
}

protected Predicate[] toCriteriaArray(Stream<Optional<? extends Predicate>> predicateStream) {
protected @Nonnull Predicate[] toCriteriaArray(@Nonnull Stream<Optional<? extends Predicate>> predicateStream) {
return predicateStream.filter(Optional::isPresent).map(Optional::get).toArray(Predicate[]::new);
}

Expand All @@ -1144,9 +1169,9 @@ protected Predicate[] toCriteriaArray(Stream<Optional<? extends Predicate>> pred
@Data
@Builder
@EqualsAndHashCode
public static final class SortState {
public static final class SortState<T, U> {

private OpenmrsFhirCriteriaContext context;
private OpenmrsFhirCriteriaContext<T, U> context;

private SortOrderEnum sortOrder;

Expand Down Expand Up @@ -1272,7 +1297,7 @@ protected <T, U> OpenmrsFhirCriteriaContext<T, U> createCriteriaContext(Class<?
CriteriaQuery<U> cq = (CriteriaQuery<U>) cb.createQuery(rootType);
@SuppressWarnings("unchecked")
Root<T> root = (Root<T>) cq.from(rootType);

return new OpenmrsFhirCriteriaContext<>(em, cb, cq, root);
}

Expand All @@ -1284,13 +1309,13 @@ protected <T, U> OpenmrsFhirCriteriaContext<T, U> createCriteriaContext(Class<?
"Tried to reference alias " + alias + " before creating a join with that name"));
}
}

protected <T, U> From<?, ?> getRootOrJoin(OpenmrsFhirCriteriaContext<T, U> criteriaContext, From<?,?> alias) {
protected <T, U> From<?, ?> getRootOrJoin(OpenmrsFhirCriteriaContext<T, U> criteriaContext, From<?, ?> alias) {
if (alias == null) {
return criteriaContext.getRoot();
} else {
return criteriaContext.getJoin(alias).orElseThrow(() -> new IllegalStateException(
"Tried to reference alias " + alias + " before creating a join with that name"));
"Tried to reference alias " + alias + " before creating a join with that name"));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Selection;

Expand Down Expand Up @@ -158,20 +159,20 @@ protected <U> OpenmrsFhirCriteriaContext<T, U> getSearchResultCriteria(SearchPar

return criteriaContext;
}

@Override
@SuppressWarnings({ "unchecked", "UnstableApiUsage" })
public List<T> getSearchResults(@Nonnull SearchParameterMap theParams) {
List<T> results;
OpenmrsFhirCriteriaContext<T, ?> criteriaContext = getSearchResultCriteria(theParams);
String idProperty = getIdPropertyName(criteriaContext);

handleSort(criteriaContext, theParams.getSortSpec());
handleIdPropertyOrdering(criteriaContext, idProperty);

TypedQuery<T> executableQuery = (TypedQuery<T>) criteriaContext.getEntityManager()
.createQuery(criteriaContext.finalizeQuery());

.createQuery(criteriaContext.finalizeQuery());
executableQuery.setFirstResult(theParams.getFromIndex());
if (theParams.getToIndex() != Integer.MAX_VALUE) {
int maxResults = theParams.getToIndex() - theParams.getFromIndex();
Expand All @@ -183,38 +184,39 @@ public List<T> getSearchResults(@Nonnull SearchParameterMap theParams) {
executableQuery.setMaxResults(negative);
}
}

if (hasDistinctResults()) {
results = (List<T>) criteriaContext.getEntityManager().createQuery(criteriaContext.getCriteriaQuery())
.getResultList();
results = executableQuery.getResultList();
} else {
List<Selection<?>> selectionList = new ArrayList<>();
selectionList.add(criteriaContext.getRoot().get(idProperty).alias("id"));
criteriaContext.getCriteriaQuery().multiselect(selectionList).distinct(true);

criteriaContext.getCriteriaQuery().select(criteriaContext.getRoot().get(getIdPropertyName(criteriaContext)))
.distinct(true);

.distinct(true);
List<Integer> ids = new ArrayList<>();
if (selectionList.size() > 1) {
for (Object[] o : ((List<Object[]>) criteriaContext.getEntityManager().createQuery(criteriaContext.getCriteriaQuery()).getResultList())) {
for (Object[] o : ((List<Object[]>) criteriaContext.getEntityManager()
.createQuery(criteriaContext.getCriteriaQuery()).getResultList())) {
ids.add((Integer) o[0]);
}
} else {
ids = (List<Integer>) criteriaContext.getEntityManager().createQuery(criteriaContext.getCriteriaQuery()).getResultList();
ids = (List<Integer>) criteriaContext.getEntityManager().createQuery(criteriaContext.getCriteriaQuery())
.getResultList();
}

// Use distinct ids from the original query to return entire objects
OpenmrsFhirCriteriaContext<T, T> wrapperQuery = createCriteriaContext(typeToken.getRawType());
wrapperQuery.getCriteriaQuery().where(wrapperQuery.getRoot().get(idProperty).in(ids));

// Need to reapply ordering
handleSort(criteriaContext, theParams.getSortSpec());
handleIdPropertyOrdering(criteriaContext, idProperty);

results = wrapperQuery.getEntityManager().createQuery(wrapperQuery.getCriteriaQuery()).getResultList();
}

return results.stream().map(this::deproxyResult).collect(Collectors.toList());
}

Expand Down Expand Up @@ -329,20 +331,18 @@ protected <U> void setupSearchParams(OpenmrsFhirCriteriaContext<T, U> criteriaCo

@Override
protected <V, U> Collection<javax.persistence.criteria.Order> paramToProps(
OpenmrsFhirCriteriaContext<V, U> criteriaContext, @Nonnull SortState sortState) {
OpenmrsFhirCriteriaContext<V, U> criteriaContext, @Nonnull SortState<V, U> sortState) {
String param = sortState.getParameter();

if (FhirConstants.SP_LAST_UPDATED.equalsIgnoreCase(param)) {
if (isImmutable) {
switch (sortState.getSortOrder()) {
case ASC:
return Collections
.singletonList((javax.persistence.criteria.Order) criteriaContext.getCriteriaQuery().orderBy(
criteriaContext.getCriteriaBuilder().asc(criteriaContext.getRoot().get("dateCreated"))));
return Collections.singletonList(
criteriaContext.getCriteriaBuilder().asc(criteriaContext.getRoot().get("dateCreated")));
case DESC:
return Collections.singletonList(
(javax.persistence.criteria.Order) criteriaContext.getCriteriaQuery().orderBy(
criteriaContext.getCriteriaBuilder().desc(criteriaContext.getRoot().get("dateCreated"))));
criteriaContext.getCriteriaBuilder().desc(criteriaContext.getRoot().get("dateCreated")));
}
}

Expand All @@ -358,14 +358,14 @@ protected <V, U> Collection<javax.persistence.criteria.Order> paramToProps(
}

@Override
protected <V, U> String paramToProp(OpenmrsFhirCriteriaContext<V, U> criteriaContext, @Nonnull String param) {
protected <V, U> Path<?> paramToProp(OpenmrsFhirCriteriaContext<V, U> criteriaContext, @Nonnull String param) {
if (DomainResource.SP_RES_ID.equals(param)) {
return "uuid";
return criteriaContext.getRoot().get("uuid");
}

return super.paramToProp(criteriaContext, param);
}

@SuppressWarnings("unchecked")
protected <V, U> void applyExactTotal(OpenmrsFhirCriteriaContext<V, U> criteriaContext, SearchParameterMap theParams) {
List<PropParam<?>> exactTotal = theParams.getParameters(EXACT_TOTAL_SEARCH_PARAMETER);
Expand Down
Loading

0 comments on commit f9adbcf

Please sign in to comment.