Skip to content

Commit

Permalink
Merge pull request #25 from i3l/patient_operations
Browse files Browse the repository at this point in the history
patient history feature using envers
  • Loading branch information
ismael-sarmento-jr committed Jul 22, 2015
2 parents 103cefb + 326b6ef commit ce1de66
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 96 deletions.
17 changes: 1 addition & 16 deletions gt-fhir-overlay/src/main/webapp/WEB-INF/templates/resource.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,11 @@
<!-- ** Default Home ** -->
<!-- ********************************************************** -->

<div class="well">
This is a RESTful server tester, which can be used to send
requests to, and receive responses from the server at the
following URL:
</div>

<!-- ************************************************ -->
<!-- ** Resource Actions ** -->
<!-- ************************************************ -->

<div class="panel panel-default" th:if="${resourceName.empty} == false">
<div class="panel-heading">
<h3 class="panel-title" th:text="'Resource: ' + ${resourceName}">Resource: <b>Patient</b></h3>
</div>
<div class="panel-body">
This page contains various operations for interacting with
the <th:block th:text="${resourceName}"/> resource.
</div>
</div>


<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist" id="resource-nav-tabs">
<!-- Search Tab -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@
import javax.persistence.Table;

import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode;

@Entity
@Table(name="concept")
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
@Audited
public class Concept {

@Id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

Expand All @@ -30,31 +30,53 @@ public class OmopConceptMapping implements Runnable {
private EntityManager entityManager;

public static final String GENDER = "Gender";
protected Map<String, List<Concept>> concepts = new HashMap<String, List<Concept>>();
public static final String MARITAL_STATUS = "Marital Status";
private static final String GENDER_VOCABULARY = "HL7 Administrative Sex";

/**
* A mapping for some of the existing concepts in the database. The key for the outter mapping is the Concept Class.
* The inner map has the value(name) of the Concept as key and the respective id in the database as values in the map.
*/
protected Map<String, Map<String, Long>> concepts = new HashMap<String, Map<String, Long>>();

private OmopConceptMapping(){}

public void loadConcepts(){
concepts.put(GENDER, getGenderClassConcept());
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
concepts.put(GENDER, findConceptMap(builder, GENDER, GENDER_VOCABULARY));
}

public static OmopConceptMapping getInstance(){
return omopConceptMapping;
}

public List<Concept> getGenderClassConcept(){
CriteriaBuilder builder = entityManager.getCriteriaBuilder();//FIXME
CriteriaQuery<Concept> criteria = builder.createQuery(Concept.class);
/**
* Searches on the database for the concepts, using, as filters, the concept class and the respective vocabulary name.
* @param builder
* @param conceptClass
* @param vocabularyName
* @return A map containing the names(values) of the concepts and their respective id's in the database.
*/
private Map<String, Long> findConceptMap(CriteriaBuilder builder, String conceptClass, String vocabularyName){
CriteriaQuery<Object[]> criteria = builder.createQuery(Object[].class);
Root<Concept> from = criteria.from(Concept.class);
Expression<Long> idPath = from.get("id").as(Long.class);
Expression<String> namePath = from.get("name").as(String.class);
criteria.multiselect(idPath, namePath);
Predicate p1 = builder.like(from.get("klass").as(String.class), GENDER);
Predicate p2 = builder.like(from.get("vocabulary").get("name").as(String.class), "HL7 Administrative Sex"); //WARNING test this; error prone
criteria.where(builder.and(p1, p2));
TypedQuery<Concept> query = entityManager.createQuery(criteria);
List<Concept> resultList = query.getResultList();
return resultList;
Path<Long> idPath = from.get("id");
Path<String> namePath = from.get("name");
criteria.multiselect(namePath, idPath); //TODO unit test, order matters here
Predicate p1 = builder.like(from.get("klass").as(String.class), conceptClass);
if(vocabularyName != null){
Predicate p2 = builder.like(from.get("vocabulary").get("name").as(String.class), vocabularyName);
criteria.where(builder.and(p1, p2));
} else{
criteria.where(builder.and(p1));
}
TypedQuery<Object[]> query = entityManager.createQuery(criteria);
Map<String, Long> retVal = new HashMap<String, Long>();
List<Object[]> resultList = query.getResultList();
for (Object[] result : resultList) {
retVal.put(((String)result[0]).toLowerCase(), (Long)result[1]);
}
return retVal;
}

@Override
Expand All @@ -65,17 +87,12 @@ public void run() {
loadConcepts();
}

public Concept get(String gender, String value) {
Concept retVal = null;
List<Concept> genderConcepts = concepts.get(GENDER);
for (Concept genderConcept : genderConcepts) {
if(value.equalsIgnoreCase(genderConcept.getName())){
retVal = genderConcept;
break;
}
}
public Long get(String conceptClass, String conceptValue) {
Long retVal = null;
Map<String, Long> concepts = this.concepts.get(conceptClass);
retVal = concepts.get(conceptValue.toLowerCase());
if(retVal == null){
ourLog.error("A respective value for Gender '?' could not be found in the database.",value);
ourLog.error("A respective value for ? '?' could not be found in the database.", conceptClass, conceptValue);
}
return retVal;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public class Person extends BaseResourceEntity{
@Column(name="gender_source_value")
private String genderSourceValue;

@ManyToOne
@ManyToOne(cascade={CascadeType.MERGE})
@JoinColumn(name="gender_concept_id")
private Concept genderConcept;

Expand Down Expand Up @@ -247,7 +247,7 @@ public void setRaceConcept(Concept raceConcept) {
@Override
public Patient getRelatedResource() {
Patient patient = new Patient();
patient.setId(new IdDt(this.getId()));
patient.setId(new IdDt(this.getResourceType(), String.valueOf(this.getId()), String.valueOf(this.getVersion())));

Calendar calendar = Calendar.getInstance();
calendar.set(this.yearOfBirth, this.monthOfBirth, this.dayOfBirth);
Expand All @@ -268,10 +268,9 @@ public Patient getRelatedResource() {
.setPeriod(period);
}

Concept gender = this.getGenderConcept();
if(gender != null){
if(this.genderConcept != null){
AdministrativeGenderEnum admGender = null;//TODO check if DSTU2 uses values coherent with this enum
String gName = gender.getName();
String gName = this.genderConcept.getName();
AdministrativeGenderEnum[] values = AdministrativeGenderEnum.values();
for (int i = 0; i < values.length; i++) {
if(gName.equalsIgnoreCase(values[i].getCode())){
Expand Down Expand Up @@ -317,9 +316,9 @@ public IResourceEntity constructEntityFromResource(IResource resource) {
this.dayOfBirth = c.get(Calendar.DAY_OF_MONTH);
//TODO set deceased value in Person; Set gender concept (source value is set); list of addresses (?)
// this.death = patient.getDeceased();
String gender = patient.getGender();
this.genderSourceValue = gender;
this.genderConcept = OmopConceptMapping.getInstance().get(OmopConceptMapping.GENDER, patient.getGender());
if(this.genderConcept == null)
this.genderConcept = new Concept();
this.genderConcept.setId(OmopConceptMapping.getInstance().get(OmopConceptMapping.GENDER, patient.getGender()));

LocationFhirExtTable location;
if(this.location != null){
Expand All @@ -330,7 +329,7 @@ public IResourceEntity constructEntityFromResource(IResource resource) {
AddressDt address = patient.getAddress().get(0);
location.setAddressUse(address.getUseElement().getValueAsEnum());
location.setAddress1(address.getLine().iterator().next().getValue());
if (address.getLine().iterator().hasNext())
if (address.getLine().size() > 1)// iterator.hasNext or listIterator.hasNext were returning true in all cases
location.setAddress2(address.getLine().iterator().next().getValue());
location.setZipCode(address.getPostalCode());
location.setCity(address.getCity());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.envers.Audited;

@Entity
@Table(name="vocabulary")
@Audited
public class Vocabulary {

@Id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;

import org.hibernate.envers.Audited;

import ca.uhn.fhir.jpa.entity.IResourceEntity;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.StringDt;
import edu.gatech.i3l.jpa.model.omop.Concept;
import edu.gatech.i3l.jpa.model.omop.Person;

/**
Expand All @@ -22,6 +27,7 @@
@Entity
@Table(name="f_person")
@PrimaryKeyJoinColumn(name="person_id")
@Audited
public class PatientFhirExtTable extends Person{

private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PatientFhirExtTable.class);
Expand All @@ -47,8 +53,9 @@ public class PatientFhirExtTable extends Person{
@Column(name="ssn")
private String ssn;

@Column(name="maritalstatus_concept_id")
private String maritalStatusConceptValue;
@ManyToOne
@JoinColumn(name="maritalstatus_concept_id")
private Concept maritalStatus;

@Column(name="active")
private Boolean active;
Expand All @@ -57,30 +64,6 @@ public PatientFhirExtTable() {
super();
}

// public PatientFhirExtTable(Long id, Integer yearOfBirth,
// Integer monthOfBirth, Integer dayOfBirth, Location location,
// Provider provider, String personSourceValue,
// String genderSourceValue, Concept genderConcept,
// String ethnicitySourceValue, Concept ethnicityConcept,
// String raceSourceValue, Concept raceConcept,
// String familyName, String givenName1,
// String givenName2, String prefixName, String suffixName,
// String preferredLanguage, String ssn,
// String maritalStatusConceptValue) {
// super(id, yearOfBirth, monthOfBirth, dayOfBirth, location, provider,
// personSourceValue, genderSourceValue, genderConcept,
// ethnicitySourceValue, ethnicityConcept, raceSourceValue,
// raceConcept);
// this.familyName = familyName;
// this.givenName1 = givenName1;
// this.givenName2 = givenName2;
// this.prefixName = prefixName;
// this.suffixName = suffixName;
// this.preferredLanguage = preferredLanguage;
// this.ssn = ssn;
// this.maritalStatusConceptValue = maritalStatusConceptValue;
// }

public String getFamilyName() {
return familyName;
}
Expand Down Expand Up @@ -137,12 +120,12 @@ public void setSsn(String ssn) {
this.ssn = ssn;
}

public String getMaritalStatusConceptValue() {
return maritalStatusConceptValue;
public Concept getMaritalStatus() {
return maritalStatus;
}

public void setMaritalStatusConceptValue(String maritalStatusConceptValue) {
this.maritalStatusConceptValue = maritalStatusConceptValue;
public void setMaritalStatus(Concept maritalStatus) {
this.maritalStatus = maritalStatus;
}

public Boolean getActive() {
Expand All @@ -161,9 +144,23 @@ public Patient getRelatedResource() {
patient.getName().get(0).addGiven(this.givenName2);
boolean active = this.active != null ? this.active : false;
patient.setActive(active);

//MARITAL STATUS
// MaritalStatusCodesEnum[] values = MaritalStatusCodesEnum.values();
// for (int i = 0; i < values.length; i++) {
// if(values[i].equals(this.maritalStatus.getName())){
// patient.setMaritalStatus(values[i]);
// break;
// }
// }
// or patient.setMaritalStatus(MaritalStatusCodesEnum.valueOf(""));
return patient;
}


/**
* @notice In Fhir model, {@link Patient} has a collection of names, while in this extension table, {@link PatientFhirExtTable},
* there is only one name for each {@link Person}.
*/
@Override
public IResourceEntity constructEntityFromResource(IResource resource) {
super.constructEntityFromResource(resource);
Expand All @@ -172,23 +169,26 @@ public IResourceEntity constructEntityFromResource(IResource resource) {

Iterator<HumanNameDt> iterator = patient.getName().iterator();
//while(iterator.hasNext()){
HumanNameDt next = iterator.next();
this.givenName1 = next.getGiven().iterator().next().getValue();
if(next.getGiven().iterator().hasNext())
this.givenName2 = next.getGiven().iterator().next().getValue();
Iterator<StringDt> family = next.getFamily().iterator();
this.familyName = "";
while(family.hasNext()){
this.familyName = this.familyName.concat(family.next().getValue()+" ");
if(iterator.hasNext()){
HumanNameDt next = iterator.next();
this.givenName1 = next.getGiven().get(0).getValue();//the next method was not advancing to the next element, then the need to use the get(index) method
if(next.getGiven().size() > 1) //TODO add unit tests, to assure this won't be changed to hasNext
this.givenName2 = next.getGiven().get(1).getValue();
Iterator<StringDt> family = next.getFamily().iterator();
this.familyName = "";
while(family.hasNext()){
this.familyName = this.familyName.concat(family.next().getValue()+" ");
}
if(next.getSuffix().iterator().hasNext())
this.suffixName = next.getSuffix().iterator().next().getValue();
if(next.getPrefix().iterator().hasNext())
this.prefixName = next.getPrefix().iterator().next().getValue();
}
if(next.getSuffix().iterator().hasNext())
this.suffixName = next.getSuffix().iterator().next().getValue();
if(next.getPrefix().iterator().hasNext())
this.prefixName = next.getPrefix().iterator().next().getValue();
//}

this.active = patient.getActive();
this.maritalStatusConceptValue = patient.getMaritalStatus().getText();
//MARITAL STATUS
// this.maritalStatus.setId(OmopConceptMapping.getInstance().get(OmopConceptMapping.MARITAL_STATUS, patient.getMaritalStatus().getText()));
} else {
ourLog.error("There was not possible to construct the entity ? using the resource ?. It should be used the resource ?.",
this.getClass().getSimpleName(), resource.getResourceName(), getResourceType());
Expand Down
1 change: 1 addition & 0 deletions gt-fhir-webapp/src/main/resources/META-INF/persistence.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<property name="hibernate.cache.use_query_cache" value="false" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
<property name="hibernate.cache.use_structured_entries" value="false" />
<property name="org.hibernate.envers.audit_strategy" value="org.hibernate.envers.strategy.ValidityAuditStrategy"/>
</properties>
</persistence-unit>
</persistence>

0 comments on commit ce1de66

Please sign in to comment.