diff --git a/api/src/main/java/org/openmrs/Cohort.java b/api/src/main/java/org/openmrs/Cohort.java index 881a128cc32..2eb0a8a86fe 100644 --- a/api/src/main/java/org/openmrs/Cohort.java +++ b/api/src/main/java/org/openmrs/Cohort.java @@ -9,6 +9,14 @@ */ package org.openmrs; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import org.apache.commons.lang3.StringUtils; import org.hibernate.envers.Audited; @@ -23,22 +31,30 @@ * This class represents a list of patientIds. */ @Audited +@Entity +@Table(name = "cohort") public class Cohort extends BaseChangeableOpenmrsData { - + public static final long serialVersionUID = 0L; - + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "cohort_id") private Integer cohortId; - + + @Column(name = "name", nullable = false) private String name; - + + @Column(name = "description", nullable = false, length = 1000) private String description; - + + @OneToMany(mappedBy = "cohort", cascade = CascadeType.ALL, orphanRemoval = true) private Collection memberships; - + public Cohort() { memberships = new TreeSet<>(); } - + /** * Convenience constructor to create a Cohort object that has an primarykey/internal identifier * of cohortId @@ -49,12 +65,11 @@ public Cohort(Integer cohortId) { this(); this.cohortId = cohortId; } - + /** * This constructor does not check whether the database contains patients with the given ids, * but {@link org.openmrs.api.CohortService#saveCohort(Cohort)} will. - * - * @param name + * * @param name * @param description optional description * @param ids option array of Integer ids */ @@ -66,12 +81,11 @@ public Cohort(String name, String description, Integer[] ids) { Arrays.stream(ids).forEach(this::addMember); } } - + /** * This constructor does not check whether the database contains patients with the given ids, * but {@link org.openmrs.api.CohortService#saveCohort(Cohort)} will. - * - * @param name + * * @param name * @param description optional description * @param patients optional array of patients */ @@ -81,26 +95,24 @@ public Cohort(String name, String description, Patient[] patients) { Arrays.stream(patients).forEach(p -> addMembership(new CohortMembership(p.getPatientId()))); } } - + /** * This constructor does not check whether the database contains patients with the given ids, * but {@link org.openmrs.api.CohortService#saveCohort(Cohort)} will. - * - * @param patientsOrIds optional collection which may contain Patients, or patientIds which may - * be Integers, Strings, or anything whose toString() can be parsed to an Integer. + * * @param patientsOrIds optional collection which may contain Patients, or patientIds which may + * be Integers, Strings, or anything whose toString() can be parsed to an Integer. */ public Cohort(Collection patientsOrIds) { this(null, null, patientsOrIds); } - + /** * This constructor does not check whether the database contains patients with the given ids, * but {@link org.openmrs.api.CohortService#saveCohort(Cohort)} will. - * - * @param name + * * @param name * @param description optional description * @param patientsOrIds optional collection which may contain Patients, or patientIds which may - * be Integers, Strings, or anything whose toString() can be parsed to an Integer. + * be Integers, Strings, or anything whose toString() can be parsed to an Integer. */ public Cohort(String name, String description, Collection patientsOrIds) { this(name, description, (Integer[]) null); @@ -114,20 +126,19 @@ public Cohort(String name, String description, Collection patientsOrIds) { } } } - + /** * Convenience constructor taking in a string that is a list of comma separated patient ids This * constructor does not check whether the database contains patients with the given ids, but * {@link org.openmrs.api.CohortService#saveCohort(Cohort)} will. - * - * @param commaSeparatedIds + * * @param commaSeparatedIds */ public Cohort(String commaSeparatedIds) { this(); String[] ids = StringUtils.split(commaSeparatedIds, ','); Arrays.stream(ids).forEach(id -> addMembership(new CohortMembership(Integer.valueOf(id.trim())))); } - + /** * @deprecated since 2.1.0 cohorts are more complex than just a set of patient ids, so there is no one-line replacement * @return Returns a comma-separated list of patient ids in the cohort. @@ -136,12 +147,12 @@ public Cohort(String commaSeparatedIds) { public String getCommaSeparatedPatientIds() { return StringUtils.join(getMemberIds(), ','); } - + public boolean contains(Integer patientId) { return getMemberships() != null - && getMemberships().stream().anyMatch(m -> m.getPatientId().equals(patientId) && !m.getVoided()); + && getMemberships().stream().anyMatch(m -> m.getPatientId().equals(patientId) && !m.getVoided()); } - + @Override public String toString() { StringBuilder sb = new StringBuilder("Cohort id=" + getCohortId()); @@ -153,11 +164,11 @@ public String toString() { } return sb.toString(); } - + public void addMember(Integer memberId) { this.addMembership(new CohortMembership(memberId)); } - + /** * @since 2.1.0 */ @@ -168,14 +179,14 @@ public boolean addMembership(CohortMembership cohortMembership) { } return false; } - + /** * @since 2.1.0 */ public boolean removeMembership(CohortMembership cohortMembership) { return getMemberships().remove(cohortMembership); } - + /** * @since 2.1.0 * @param includeVoided boolean true/false to include/exclude voided memberships @@ -187,7 +198,7 @@ public Collection getMemberships(boolean includeVoided) { } return getMemberships().stream().filter(m -> m.getVoided() == includeVoided).collect(Collectors.toList()); } - + /** * @since 2.1.0 */ @@ -197,7 +208,7 @@ public Collection getMemberships() { } return memberships; } - + /** * @since 2.1.0 * @param asOfDate date used to return active memberships @@ -206,23 +217,23 @@ public Collection getMemberships() { public Collection getActiveMemberships(Date asOfDate) { return getMemberships().stream().filter(m -> m.isActive(asOfDate)).collect(Collectors.toList()); } - + public Collection getActiveMemberships() { return getActiveMemberships(new Date()); } - + /** * @since 2.1.0 */ public CohortMembership getActiveMembership(Patient patient) { return getMemberships().stream().filter(m -> m.isActive() && m.getPatientId().equals(patient.getPatientId())).findFirst().get(); } - + public int size() { return getMemberships().stream().filter(m -> !m.getVoided()).collect(Collectors.toList()) - .size(); + .size(); } - + /** * @deprecated use {@link #size()} */ @@ -230,13 +241,13 @@ public int size() { public int getSize() { return size(); } - + public boolean isEmpty() { return size() == 0; } - + // static utility methods - + /** * Returns the union of two cohorts * @@ -257,7 +268,7 @@ public static Cohort union(Cohort a, Cohort b) { } return ret; } - + /** * Returns the intersection of two cohorts, treating null as an empty cohort * @@ -274,7 +285,7 @@ public static Cohort intersect(Cohort a, Cohort b) { } return ret; } - + /** * Subtracts a cohort from a cohort * @@ -293,33 +304,33 @@ public static Cohort subtract(Cohort a, Cohort b) { } return ret; } - + // getters and setters - + public Integer getCohortId() { return cohortId; } - + public void setCohortId(Integer cohortId) { this.cohortId = cohortId; } - + public String getDescription() { return description; } - + public void setDescription(String description) { this.description = description; } - + public String getName() { return name; } - + public void setName(String name) { this.name = name; } - + /** * @deprecated since 2.1.0 cohorts are more complex than just a set of patient ids, so there is no one-line replacement */ @@ -331,7 +342,7 @@ public Set getMemberIds() { } return memberIds; } - + /** * @deprecated since 2.1.0 cohorts are more complex than just a set of patient ids, so there is no one-line replacement * @param memberIds @@ -347,21 +358,21 @@ public void setMemberIds(Set memberIds) { throw new IllegalArgumentException("since 2.1.0 cohorts are more complex than just a set of patient ids"); } } - + public void setMemberships(Collection members) { this.memberships = members; } - + /** * @since 1.5 * @see org.openmrs.OpenmrsObject#getId() */ @Override public Integer getId() { - + return getCohortId(); } - + /** * @since 1.5 * @see org.openmrs.OpenmrsObject#setId(java.lang.Integer) @@ -369,38 +380,34 @@ public Integer getId() { @Override public void setId(Integer id) { setCohortId(id); - + } - + /** * @since 2.3 - * - * This function checks if there exists any active CohortMembership for a given patientId - * - * @param patientId is the patientid that should be checked for activity in cohort + * * This function checks if there exists any active CohortMembership for a given patientId + * * @param patientId is the patientid that should be checked for activity in cohort * @return true if cohort has active membership for the requested patient */ public boolean hasActiveMembership(int patientId) { return getMemberships().stream().anyMatch(m -> m.getPatientId() == patientId && m.isActive()); } - + /** - * - * @since 2.3 + * * @since 2.3 * This method returns the number of active members in the cohort - * - * @return number of active memberships in the cohort + * * @return number of active memberships in the cohort */ public int activeMembershipSize() { return getActiveMemberships().size(); } - + /** * * @since 2.3 * This method returns true if cohort has no active memberships * - * @return true if no active cohort exists + * @return true if no active cohort exist **/ public boolean hasNoActiveMemberships() { return getActiveMemberships().isEmpty(); diff --git a/api/src/main/java/org/openmrs/CohortMembership.java b/api/src/main/java/org/openmrs/CohortMembership.java index f459f784756..061c1f1c92d 100644 --- a/api/src/main/java/org/openmrs/CohortMembership.java +++ b/api/src/main/java/org/openmrs/CohortMembership.java @@ -1,3 +1,12 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under + * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. + * + * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS + * graphic logo is a trademark of OpenMRS Inc. + */ /** * This Source Code Form is subject to the terms of the Mozilla Public License, * v. 2.0. If a copy of the MPL was not distributed with this file, You can @@ -9,43 +18,61 @@ */ package org.openmrs; -import java.util.Date; -import java.util.Objects; - +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import org.hibernate.envers.Audited; import org.openmrs.util.OpenmrsUtil; +import java.util.Date; +import java.util.Objects; + /** * @since 2.1.0 */ @Audited +@Entity +@Table(name = "cohort_member") public class CohortMembership extends BaseChangeableOpenmrsData implements Comparable { - + public static final long serialVersionUID = 0L; + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "cohort_member_id") private Integer cohortMemberId; - + + @ManyToOne(optional = false) + @JoinColumn(name = "cohort_id", nullable = false) private Cohort cohort; - + + @Column(name = "patient_id", nullable = false) private Integer patientId; - + + @Column(name = "start_date", nullable = false) private Date startDate; - + + @Column(name = "end_date") private Date endDate; - + // Constructor public CohortMembership() { } - + public CohortMembership(Integer patientId, Date startDate) { this.patientId = patientId; this.startDate = startDate; } - + public CohortMembership(Integer patientId) { this(patientId, new Date()); } - + /** * Compares asOfDate to [startDate, endDate], inclusive of both endpoints. * @param asOfDate date to compare if membership is active or inactive @@ -56,57 +83,57 @@ public boolean isActive(Date asOfDate) { return !this.getVoided() && OpenmrsUtil.compare(startDate, date) <= 0 && OpenmrsUtil.compareWithNullAsLatest(date, endDate) <= 0; } - + public boolean isActive() { return isActive(null); } - + @Override public Integer getId() { return getCohortMemberId(); } - + @Override public void setId(Integer id) { setCohortMemberId(id); } - + public Integer getCohortMemberId() { return cohortMemberId; } - + public void setCohortMemberId(Integer cohortMemberId) { this.cohortMemberId = cohortMemberId; } - + public Cohort getCohort() { return cohort; } - + public void setCohort(Cohort cohort) { this.cohort = cohort; } - + public Integer getPatientId() { return patientId; } - + public void setPatientId(Integer patientId) { this.patientId = patientId; } - + public Date getStartDate() { return startDate != null ? (Date) startDate.clone() : null; } - + public void setStartDate(Date startDate) { - this.startDate = startDate != null ? new Date(startDate.getTime()) : null; + this.startDate = startDate != null ? new Date(startDate.getTime()) : null; } - + public Date getEndDate() { return endDate != null ? (Date) endDate.clone() : null; } - + /** * OpenMRS treats a membership as active from its startDate to endDate inclusive of both. * The underlying database field stores a date+time, so in the common case (where you don't care about the time of day @@ -116,34 +143,33 @@ public Date getEndDate() { public void setEndDate(Date endDate) { this.endDate = endDate != null ? new Date(endDate.getTime()) : null; } - - + /** * Sorts by following fields, in order: *
    - *
  1. voided (voided memberships sort last)
  2. - *
  3. endDate descending (so ended memberships are towards the end, and the older the more towards the end
  4. - *
  5. startDate descending (so started more recently is towards the front)
  6. - *
  7. patientId ascending (intuitive and consistent tiebreaker for client code)
  8. - *
  9. uuid ascending (just so we have a final consistent tie breaker)
  10. + *
  11. voided (voided memberships sort last)
  12. + *
  13. endDate descending (so ended memberships are towards the end, and the older the more towards the end
  14. + *
  15. startDate descending (so started more recently is towards the front)
  16. + *
  17. patientId ascending (intuitive and consistent tiebreaker for client code)
  18. + *
  19. uuid ascending (just so we have a final consistent tie breaker)
  20. *
* * @param o other membership to compare this to * @return value greater than 0 if this is not voided and o is voided; or value less - * than 0 if this is voided and o is not voided; if both is voided or not then - * value greater than 0 if o.getEndDate() return null; or value less than - * 0 if this.getEndDate() return null; if both are null or not then value - * greater than 0 if this.getEndDate() is before o.getEndDate(); or value less - * than 0 if this.getEndDate() is after o.getEndDate(); if are equal then value - * greater than 0 if this.getStartDate() return null; or value less than - * 0 if o.getStartDate() return null; if both are null or not then value greater - * than 0 if this.getStartDate() is before o.getStartDate(); or value less than - * 0 if this.getStartDate() is after o.getStartDate(); if are equal then value - * greater than 0 if o.getPatientId() is greater than this.getPatientId(); or - * value less than 0 if o.getPatientId() is less than this.getPatientId(); if - * are equal then value greater than 0 if o.getUuid() is greater than - * this.getUuid(); or value less than 0 if o.getUuid() is less than - * this.getUuid(); or 0 if are equal + * than 0 if this is voided and o is not voided; if both is voided or not then + * value greater than 0 if o.getEndDate() return null; or value less than + * 0 if this.getEndDate() return null; if both are null or not then value + * greater than 0 if this.getEndDate() is before o.getEndDate(); or value less + * than 0 if this.getEndDate() is after o.getEndDate(); if are equal then value + * greater than 0 if this.getStartDate() return null; or value less than + * 0 if o.getStartDate() return null; if both are null or not then value greater + * than 0 if this.getStartDate() is before o.getStartDate(); or value less than + * 0 if this.getStartDate() is after o.getStartDate(); if are equal then value + * greater than 0 if o.getPatientId() is greater than this.getPatientId(); or + * value less than 0 if o.getPatientId() is less than this.getPatientId(); if + * are equal then value greater than 0 if o.getUuid() is greater than + * this.getUuid(); or value less than 0 if o.getUuid() is less than + * this.getUuid(); or 0 if are equal */ @Override public int compareTo(CohortMembership o) { @@ -162,36 +188,35 @@ public int compareTo(CohortMembership o) { } return ret; } - + /** * @since 2.3.0 * Indicates if a given cohortMembership object is equal to this one - * - * @param otherCohortMembershipObject is a CohortMembership object that should be checked for equality with this object + * * @param otherCohortMembershipObject is a CohortMembership object that should be checked for equality with this object * @return true if both objects are logically equal. This is the case when endDate, startDate and patientId are equal */ @Override public boolean equals(Object otherCohortMembershipObject) { - if(otherCohortMembershipObject == null || !(otherCohortMembershipObject instanceof CohortMembership)){ + if (otherCohortMembershipObject == null || !(otherCohortMembershipObject instanceof CohortMembership)) { return false; } - CohortMembership otherCohortMembership = (CohortMembership)otherCohortMembershipObject; - if(this == otherCohortMembership){ + CohortMembership otherCohortMembership = (CohortMembership) otherCohortMembershipObject; + if (this == otherCohortMembership) { return true; - } - - - return ((endDate != null ) ? endDate.equals(otherCohortMembership.getEndDate()) : otherCohortMembership.getEndDate() == null) - && - ((startDate !=null) ? startDate.equals(otherCohortMembership.getStartDate()) : otherCohortMembership.getStartDate() == null) - && - ((patientId != null) ? patientId.equals(otherCohortMembership.getPatientId()) : otherCohortMembership.getPatientId() == null); + } + + return ((endDate != null) ? endDate.equals(otherCohortMembership.getEndDate()) + : otherCohortMembership.getEndDate() == null) + && ((startDate != null) ? startDate.equals(otherCohortMembership.getStartDate()) + : otherCohortMembership.getStartDate() == null) + && ((patientId != null) ? patientId.equals(otherCohortMembership.getPatientId()) + : otherCohortMembership.getPatientId() == null); } + /** * @since 2.3.0 - * - * Creates a hash code of this object - */ + * * Creates a hash code of this object + */ @Override public int hashCode() { return Objects.hash(patientId, endDate, startDate); diff --git a/api/src/main/resources/hibernate.cfg.xml b/api/src/main/resources/hibernate.cfg.xml index 3a12ab71b2b..aff97a6d6a3 100644 --- a/api/src/main/resources/hibernate.cfg.xml +++ b/api/src/main/resources/hibernate.cfg.xml @@ -54,8 +54,8 @@ - - + + diff --git a/api/src/main/resources/org/openmrs/api/db/hibernate/Cohort.hbm.xml b/api/src/main/resources/org/openmrs/api/db/hibernate/Cohort.hbm.xml deleted file mode 100644 index 56f0a9c2cd2..00000000000 --- a/api/src/main/resources/org/openmrs/api/db/hibernate/Cohort.hbm.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - cohort_cohort_id_seq - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/api/src/main/resources/org/openmrs/api/db/hibernate/CohortMembership.hbm.xml b/api/src/main/resources/org/openmrs/api/db/hibernate/CohortMembership.hbm.xml deleted file mode 100644 index ddf4ab65669..00000000000 --- a/api/src/main/resources/org/openmrs/api/db/hibernate/CohortMembership.hbm.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - cohort_member_cohort_member_id_seq - - - - - - - - - - - - - - - - - - - - -