Skip to content

Commit

Permalink
Add Icd10ExpanderDecorator
Browse files Browse the repository at this point in the history
  • Loading branch information
tommydeboer committed Aug 23, 2018
1 parent 48912f0 commit 84e491a
Show file tree
Hide file tree
Showing 9 changed files with 642 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.molgenis.data.icd10;

import org.molgenis.data.Entity;
import org.molgenis.data.Query;

/**
* Transforms a query on an attribute that refers to a ICD-10 repository
*/
public interface CollectionsQueryTransformer
{
/**
* @param query the query to transform
* @param icd10EntityTypeId the EntityType that contains the ICD-10 identifiers
* @param expandAttribute the attribute on which to apply the query transformation
* @return a query containing expanded ICD-10 codes
*/
Query<Entity> transformQuery(Query<Entity> query, String icd10EntityTypeId, String expandAttribute);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.molgenis.data.icd10;

import com.google.common.collect.TreeTraverser;
import org.molgenis.data.DataService;
import org.molgenis.data.Entity;
import org.molgenis.data.Query;
import org.molgenis.data.QueryRule;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;

import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;

@Component
public class CollectionsQueryTransformerImpl implements CollectionsQueryTransformer
{
private static final TreeTraverser<QueryRule> RULE_TRAVERSER = TreeTraverser.using(QueryRule::getNestedRules);

private final Icd10ClassExpander icd10ClassExpander;
private final DataService dataService;

CollectionsQueryTransformerImpl(Icd10ClassExpander icd10ClassExpander, DataService dataService)
{
this.icd10ClassExpander = requireNonNull(icd10ClassExpander);
this.dataService = requireNonNull(dataService);
}

@Override
public Query<Entity> transformQuery(Query<Entity> query, String icd10EntityTypeId, String expandAttribute)
{
if (query != null && query.getRules() != null && !query.getRules().isEmpty())
{
query.getRules()
.forEach(rule -> RULE_TRAVERSER.preOrderTraversal(rule)
.filter(nestedRule -> isTransformableRule(nestedRule, expandAttribute))
.forEach(nestedRule -> transformQueryRule(nestedRule,
icd10EntityTypeId)));
}

return query;
}

private void transformQueryRule(QueryRule rule, String icd10EntityTypeId)
{
List<Object> queryValues;

switch (rule.getOperator())
{
case EQUALS:
queryValues = singletonList(rule.getValue());
rule.setOperator(QueryRule.Operator.IN);
break;
case IN:
//noinspection unchecked
queryValues = (List<Object>) rule.getValue();
break;
default:
throw new IllegalStateException("Can't expand queries other than IN or EQUALS");
}

List<Entity> diseaseTypes = dataService.findAll(icd10EntityTypeId, queryValues.stream()).collect(toList());

rule.setValue(expandDiseaseTypes(diseaseTypes));
}

/**
* Returns <code>true</code> if a rule is 'IN' or 'EQUALS' on the attribute that should be expanded
*/
private boolean isTransformableRule(QueryRule nestedRule, String expandAttribute)
{
return nestedRule != null && nestedRule.getField() != null && nestedRule.getField().equals(expandAttribute) && (
nestedRule.getOperator() == QueryRule.Operator.IN
|| nestedRule.getOperator() == QueryRule.Operator.EQUALS);
}

/**
* Expand ICD-10 entities with all their children, grandchildren, etc.
*/
private Collection<Entity> expandDiseaseTypes(List<Entity> diseaseTypes)
{
return icd10ClassExpander.expandClasses(diseaseTypes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.molgenis.data.icd10;

import org.molgenis.data.Entity;

import java.util.Collection;

/**
* Expands a list of 'eu_bbmri_eric_disease_types' entities to include all of their children.
*/
public interface Icd10ClassExpander
{
Collection<Entity> expandClasses(Collection<Entity> diseaseClasses);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.molgenis.data.icd10;

import com.google.common.collect.TreeTraverser;
import org.molgenis.data.Entity;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static java.util.stream.Collectors.toList;

@Component
public class Icd10ClassExpanderImpl implements Icd10ClassExpander
{
private static final String DISEASE_CLASS_CHILDREN_ATTRIBUTE_NAME = "children";

@Override
public Collection<Entity> expandClasses(Collection<Entity> diseaseClasses)
{
return diseaseClasses.stream()
.flatMap(this::expandClass)
.map(this::toDiseaseClass)
.distinct()
.map(this::toEntity)
.collect(toList());
}

private Stream<Entity> expandClass(Entity diseaseClass)
{
Iterable<Entity> diseaseClasses = new DiseaseClassTreeTraverser().postOrderTraversal(diseaseClass);
return StreamSupport.stream(diseaseClasses.spliterator(), false);
}

private DiseaseClass toDiseaseClass(Entity entity)
{
return new DiseaseClass(entity);
}

private Entity toEntity(DiseaseClass diseaseClass)
{
return diseaseClass.getEntity();
}

/**
* Disease class entity wrapper with equals and hashCode implementation.
*/
private static class DiseaseClass
{
private final Entity entity;

private DiseaseClass(Entity entity)
{
this.entity = entity;
}

private Entity getEntity()
{
return entity;
}

@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

DiseaseClass that = (DiseaseClass) o;

return entity.getIdValue().equals(that.entity.getIdValue());
}

@Override
public int hashCode()
{
return entity.getIdValue().hashCode();
}
}

private static class DiseaseClassTreeTraverser extends TreeTraverser<Entity>
{
@Override
public Iterable<Entity> children(@Nonnull Entity diseaseClassEntity)
{
return diseaseClassEntity.getEntities(DISEASE_CLASS_CHILDREN_ATTRIBUTE_NAME);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.molgenis.data.icd10;

import org.molgenis.data.AbstractRepositoryDecorator;
import org.molgenis.data.Entity;
import org.molgenis.data.Query;
import org.molgenis.data.Repository;
import org.molgenis.data.aggregation.AggregateQuery;
import org.molgenis.data.aggregation.AggregateResult;
import org.molgenis.data.support.AggregateQueryImpl;

import java.util.stream.Stream;

import static java.util.Objects.requireNonNull;

class Icd10ExpanderDecorator extends AbstractRepositoryDecorator<Entity>
{
private final CollectionsQueryTransformer queryTransformer;
private final String icd10EntityTypeId;
private final String expandAttribute;

Icd10ExpanderDecorator(Repository<Entity> delegateRepository, CollectionsQueryTransformer queryTransformer,
String icd10EntityTypeId, String expandAttribute)
{
super(delegateRepository);
this.queryTransformer = requireNonNull(queryTransformer);
this.icd10EntityTypeId = requireNonNull(icd10EntityTypeId);
this.expandAttribute = requireNonNull(expandAttribute);
}

@Override
public long count(Query<Entity> query)
{
query = query != null ? transformQuery(query) : null;
return delegate().count(query);
}

@Override
public Entity findOne(Query<Entity> query)
{
query = query != null ? transformQuery(query) : null;
return delegate().findOne(query);
}

@Override
public Stream<Entity> findAll(Query<Entity> query)
{
query = query != null ? transformQuery(query) : null;
return delegate().findAll(query);
}

@Override
public AggregateResult aggregate(AggregateQuery aggregateQuery)
{
Query<Entity> q = aggregateQuery.getQuery();
Query<Entity> transformedQuery = q != null ? transformQuery(q) : null;
aggregateQuery = new AggregateQueryImpl(aggregateQuery.getAttributeX(), aggregateQuery.getAttributeY(),
aggregateQuery.getAttributeDistinct(), transformedQuery);
return delegate().aggregate(aggregateQuery);
}

private Query<Entity> transformQuery(Query<Entity> query)
{
return queryTransformer.transformQuery(query, icd10EntityTypeId, expandAttribute);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.molgenis.data.icd10;

import com.google.common.collect.ImmutableList;
import com.google.gson.Gson;
import org.molgenis.data.Entity;
import org.molgenis.data.Repository;
import org.molgenis.data.decorator.DynamicRepositoryDecoratorFactory;
import org.springframework.stereotype.Component;

import java.util.Map;

import static com.google.common.collect.ImmutableMap.of;
import static java.util.Objects.requireNonNull;

@Component
@SuppressWarnings("unused")
public class Icd10ExpanderDecoratorFactory implements DynamicRepositoryDecoratorFactory<Entity>
{
private static final String ID = "icd10expander";
private static final String ICD10_ENTITY_TYPE_ID = "icd10EntityTypeId";
private static final String EXPAND_ATTRIBUTE = "expandAttribute";

private final Gson gson;
private final CollectionsQueryTransformer queryTransformer;

public Icd10ExpanderDecoratorFactory(Gson gson, CollectionsQueryTransformer queryTransformer)
{
this.gson = requireNonNull(gson);
this.queryTransformer = requireNonNull(queryTransformer);
}

@Override
@SuppressWarnings("unchecked")
public Repository createDecoratedRepository(Repository<Entity> repository, Map<String, Object> parameters)
{
return new Icd10ExpanderDecorator(repository, queryTransformer, parameters.get(ICD10_ENTITY_TYPE_ID).toString(),
parameters.get(EXPAND_ATTRIBUTE).toString());
}

@Override
public String getId()
{
return ID;
}

@Override
public String getLabel()
{
return "ICD-10 Query Expander";
}

@Override
public String getDescription()
{
return "Expands queries on an attribute that refers to an entity type with ICD-10 codes.";
}

@Override
public String getSchema()
{
return gson.toJson(of("title", "Icd10Expander", "type", "object", "properties", of(ICD10_ENTITY_TYPE_ID,
of("type", "string", "description", "The entity type containing the ICD-10 data."), EXPAND_ATTRIBUTE,
of("type", "string", "description", "The attribute on which the query expansion will be applied.")),
"required", ImmutableList.of(ICD10_ENTITY_TYPE_ID, EXPAND_ATTRIBUTE)));
}
}

Loading

0 comments on commit 84e491a

Please sign in to comment.