Skip to content

Commit

Permalink
feat: Sort & Filter attribute change logs [DHIS2-18475] (#19331)
Browse files Browse the repository at this point in the history
* feat: Migrate TEA change logs into new table [DHIS2-18474]

* feat: Fix sonar issues [DHIS2-18474]

* feat: Import one object in test[DHIS2-18474]

* feat: Lowercase sql script  [DHIS2-18474]

* feat: Address PR comments [DHIS2-18474]

* feat: Filter attribute change logs [DHIS2-18475]

* feat: Filter attribute change logs [DHIS2-18475]

* feat: Sort by date, user and attribute in change logs [DHIS2-18475]

* feat: Add comment on filter builder method [DHIS2-18475]

* feat: Add comment on filter builder method [DHIS2-18475]

* feat: Address PR comment [DHIS2-18475]
  • Loading branch information
muilpp authored Dec 3, 2024
1 parent c2e07e8 commit 9b2ce34
Show file tree
Hide file tree
Showing 11 changed files with 509 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.tuple.Pair;
import org.hisp.dhis.changelog.ChangeLogType;
import org.hisp.dhis.common.IdentifiableObject;
import org.hisp.dhis.common.UID;
Expand Down Expand Up @@ -173,6 +174,11 @@ public Set<String> getOrderableFields() {
return hibernateTrackedEntityChangeLogStore.getOrderableFields();
}

@Override
public Set<Pair<String, Class<?>>> getFilterableFields() {
return hibernateTrackedEntityChangeLogStore.getFilterableFields();
}

private Program validateProgram(String programUid) throws NotFoundException {
Program program = programService.getProgram(programUid);
if (program == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,15 @@
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.lang3.tuple.Pair;
import org.hibernate.Session;
import org.hisp.dhis.changelog.ChangeLogType;
import org.hisp.dhis.common.QueryFilter;
import org.hisp.dhis.common.SortDirection;
import org.hisp.dhis.common.UID;
import org.hisp.dhis.program.UserInfoSnapshot;
Expand All @@ -53,11 +56,22 @@
@Repository("org.hisp.dhis.tracker.export.trackedentity.HibernateTrackedEntityChangeLogStore")
public class HibernateTrackedEntityChangeLogStore {
private static final String COLUMN_CHANGELOG_CREATED = "tecl.created";
private static final String COLUMN_CHANGELOG_USER = "tecl.createdByUsername";
private static final String COLUMN_CHANGELOG_DATA_ELEMENT = "tea.uid";

private static final String DEFAULT_ORDER =
COLUMN_CHANGELOG_CREATED + " " + SortDirection.DESC.getValue();

private static final Map<String, String> ORDERABLE_FIELDS =
Map.ofEntries(entry("createdAt", COLUMN_CHANGELOG_CREATED));
Map.ofEntries(
entry("createdAt", COLUMN_CHANGELOG_CREATED),
entry("username", COLUMN_CHANGELOG_USER),
entry("attribute", COLUMN_CHANGELOG_DATA_ELEMENT));

private static final Map<Pair<String, Class<?>>, String> FILTERABLE_FIELDS =
Map.ofEntries(
entry(Pair.of("username", String.class), COLUMN_CHANGELOG_USER),
entry(Pair.of("attribute", UID.class), COLUMN_CHANGELOG_DATA_ELEMENT));

private final EntityManager entityManager;
private final Session session;
Expand Down Expand Up @@ -119,6 +133,18 @@ and tea.uid in (:attributes)
""";
}

Pair<String, QueryFilter> filter = operationParams.getFilter();
if (filter != null) {
String filterField =
FILTERABLE_FIELDS.entrySet().stream()
.filter(entry -> entry.getKey().getLeft().equals(filter.getKey()))
.findFirst()
.map(Entry::getValue)
.get();

hql += String.format(" and %s = :filterValue ", filterField);
}

hql += String.format("order by %s".formatted(sortExpressions(operationParams.getOrder())));

Query query = entityManager.createQuery(hql);
Expand All @@ -136,6 +162,10 @@ and tea.uid in (:attributes)
query.setFirstResult((pageParams.getPage() - 1) * pageParams.getPageSize());
query.setMaxResults(pageParams.getPageSize() + 1);

if (filter != null) {
query.setParameter("filterValue", filter.getValue().getFilter());
}

List<Object[]> results = query.getResultList();
List<TrackedEntityChangeLog> trackedEntityChangeLogs =
results.stream()
Expand Down Expand Up @@ -188,6 +218,10 @@ public Set<String> getOrderableFields() {
return ORDERABLE_FIELDS.keySet();
}

public Set<Pair<String, Class<?>>> getFilterableFields() {
return FILTERABLE_FIELDS.keySet();
}

private static String sortExpressions(Order order) {
if (order == null) {
return DEFAULT_ORDER;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import org.apache.commons.lang3.tuple.Pair;
import org.hisp.dhis.common.QueryFilter;
import org.hisp.dhis.common.SortDirection;
import org.hisp.dhis.tracker.export.Order;

Expand All @@ -39,6 +41,7 @@
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class TrackedEntityChangeLogOperationParams {
private Order order;
private Pair<String, QueryFilter> filter;

public static class TrackedEntityChangeLogOperationParamsBuilder {

Expand All @@ -50,10 +53,23 @@ private TrackedEntityChangeLogOperationParamsBuilder order(Order order) {
return this;
}

// Do not remove this unused method. This hides the filter field from the builder which Lombok
// does not support. The repeated filter field and private filter method prevent access to
// filter via the builder.
// Filter should be added via the filterBy builder methods.
private TrackedEntityChangeLogOperationParamsBuilder filter(Pair<String, QueryFilter> filter) {
return this;
}

public TrackedEntityChangeLogOperationParamsBuilder orderBy(
String field, SortDirection direction) {
this.order = new Order(field, direction);
return this;
}

public TrackedEntityChangeLogOperationParamsBuilder filterBy(String field, QueryFilter filter) {
this.filter = Pair.of(field, filter);
return this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.lang3.tuple.Pair;
import org.hisp.dhis.changelog.ChangeLogType;
import org.hisp.dhis.common.UID;
import org.hisp.dhis.feedback.BadRequestException;
Expand Down Expand Up @@ -86,4 +87,13 @@ Page<TrackedEntityChangeLog> getTrackedEntityChangeLog(
* PageParams)}.
*/
Set<String> getOrderableFields();

/**
* Fields the {@link #getTrackedEntityChangeLog(UID, UID, TrackedEntityChangeLogOperationParams,
* PageParams)} can filter attribute change logs by. Filtering by fields other than these, is
* considered a programmer error. Validation of user provided field names should occur before
* calling {@link #getTrackedEntityChangeLog(UID, UID, TrackedEntityChangeLogOperationParams,
* PageParams)}.
*/
Set<Pair<String, Class<?>>> getFilterableFields();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2000,6 +2000,21 @@
"id": "ja8NY4PW7Xm"
},
"valueType": "TEXT"
},
{
"displayInList": true,
"displayName": "Person Given name",
"displayShortName": "null Given name",
"id": "EIVt4l5vIOa",
"name": "Person Given name",
"searchable": true,
"trackedEntityAttribute": {
"id": "toUpdate000"
},
"trackedEntityType": {
"id": "ja8NY4PW7Xm"
},
"valueType": "TEXT"
}
],
"user": {
Expand Down
Loading

0 comments on commit 9b2ce34

Please sign in to comment.