Skip to content

Commit

Permalink
Merge pull request molgenis#7732 from tommydeboer/feature/icd10-decor…
Browse files Browse the repository at this point in the history
…ator

Add ICD-10 Expander Decorator
  • Loading branch information
bartcharbon authored Aug 24, 2018
2 parents 7625148 + 454d111 commit f6add8e
Show file tree
Hide file tree
Showing 12 changed files with 701 additions and 0 deletions.
5 changes: 5 additions & 0 deletions molgenis-app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,11 @@
<artifactId>molgenis-data-i18n</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.molgenis</groupId>
<artifactId>molgenis-data-icd10</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.molgenis</groupId>
<artifactId>molgenis-i18n</artifactId>
Expand Down
54 changes: 54 additions & 0 deletions molgenis-data-icd10/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.molgenis</groupId>
<artifactId>molgenis</artifactId>
<version>7.1.0-SNAPSHOT</version>
</parent>
<artifactId>molgenis-data-icd10</artifactId>

<name>data-icd10</name>
<description>ICD-10 related functionality</description>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>org.molgenis</groupId>
<artifactId>molgenis-data</artifactId>
<version>${project.version}</version>
</dependency>
<!-- third party dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>findbugs-annotations</artifactId>
<scope>provided</scope>
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>org.molgenis</groupId>
<artifactId>molgenis-test</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
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);
}
}
Loading

0 comments on commit f6add8e

Please sign in to comment.