SEBSERV-481 do sorting und most filtering on DB

This commit is contained in:
anhefti 2023-11-20 15:32:07 +01:00
parent 89adc8cd26
commit 8b15fddf13
5 changed files with 62 additions and 113 deletions

View file

@ -149,6 +149,7 @@ public class FinishedExam implements TemplateComposer {
this.pageService.entityTableBuilder(restService.getRestCall(GetFinishedExamClientConnectionPage.class))
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
.withPaging(this.pageSize)
.withDefaultSort(Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID)
.withStaticFilter(ClientConnection.FILTER_ATTR_EXAM_ID, examKey.modelId)
.withColumn(new ColumnDefinition<ClientConnectionData>(
@ -162,8 +163,7 @@ public class FinishedExam implements TemplateComposer {
ClientConnection.ATTR_INFO,
TABLE_COLUMN_INFO,
c -> c.clientConnection.getInfo())
.withFilter(this.infoFilter)
.sortable())
.withFilter(this.infoFilter))
.withColumn(new ColumnDefinition<ClientConnectionData>(
Domain.CLIENT_CONNECTION.ATTR_STATUS,

View file

@ -13,6 +13,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.dynamic.sql.SqlTable;
import org.springframework.beans.factory.annotation.Value;
@ -397,6 +398,25 @@ public class PaginationServiceImpl implements PaginationService {
UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord.tableNameAtRuntime(),
Domain.USER_ACTIVITY_LOG.ATTR_ID);
// Client Connection Table
final Map<String, String> ccTableMap = new HashMap<>();
ccTableMap.put(
ClientConnection.FILTER_ATTR_SESSION_ID,
ClientConnectionRecordDynamicSqlSupport.examUserSessionId.name());
ccTableMap.put(
ClientConnection.FILTER_ATTR_STATUS,
ClientConnectionRecordDynamicSqlSupport.status.name());
ccTableMap.put(
ClientConnection.FILTER_ATTR_INFO,
ClientConnectionRecordDynamicSqlSupport.clientVersion.name());
this.sortColumnMapping.put(
ClientConnectionRecordDynamicSqlSupport.clientConnectionRecord.tableNameAtRuntime(),
ccTableMap);
this.defaultSortColumn.put(
ClientConnectionRecordDynamicSqlSupport.clientConnectionRecord.tableNameAtRuntime(),
ClientConnection.FILTER_ATTR_SESSION_ID);
}
}

View file

@ -114,7 +114,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
final Predicate<ClientConnection> predicate) {
return Result.tryCatch(() -> {
final QueryExpressionDSL<MyBatis3SelectModelAdapter<List<ClientConnectionRecord>>>.QueryExpressionWhereBuilder whereClause =
QueryExpressionDSL<MyBatis3SelectModelAdapter<List<ClientConnectionRecord>>>.QueryExpressionWhereBuilder whereClause =
(filterMap.getBoolean(FilterMap.ATTR_ADD_INSITUTION_JOIN))
? this.clientConnectionRecordMapper
.selectByExample()
@ -130,6 +130,23 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
.where(
ClientConnectionRecordDynamicSqlSupport.institutionId,
isEqualToWhenPresent(filterMap.getInstitutionId()));
if (filterMap.contains(ClientConnection.FILTER_ATTR_INFO)) {
whereClause = whereClause
.and(
ClientConnectionRecordDynamicSqlSupport.clientVersion,
isLike(filterMap.getSQLWildcard(ClientConnection.FILTER_ATTR_INFO)),
or(
ClientConnectionRecordDynamicSqlSupport.clientOsName,
isLike(filterMap.getSQLWildcard(ClientConnection.FILTER_ATTR_INFO)),
or(
ClientConnectionRecordDynamicSqlSupport.clientAddress,
isLike(filterMap.getSQLWildcard(ClientConnection.FILTER_ATTR_INFO))
)
)
);
}
return whereClause
.and(
ClientConnectionRecordDynamicSqlSupport.connectionToken,

View file

@ -8,12 +8,7 @@
package ch.ethz.seb.sebserver.webservice.weblayer.api;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -106,21 +101,7 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
final FilterMap filterMap = new FilterMap(allRequestParams, request.getQueryString());
populateFilterMap(filterMap, institutionId, sort);
if (StringUtils.isNotBlank(sort) || filterMap.containsAny(EXT_FILTER)) {
final Collection<ClientConnection> allConnections = getAll(filterMap)
.getOrThrow();
return this.paginationService.buildPageFromList(
pageNumber,
pageSize,
sort,
allConnections,
pageClientConnectionFunction(filterMap, sort));
} else {
return super.getPage(institutionId, pageNumber, pageSize, sort, allRequestParams, request);
}
return super.getPage(institutionId, pageNumber, pageSize, sort, allRequestParams, request);
}
@RequestMapping(
@ -145,7 +126,7 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
final FilterMap filterMap = new FilterMap(allRequestParams, request.getQueryString());
populateFilterMap(filterMap, institutionId, sort);
if (StringUtils.isNotBlank(sort) || filterMap.containsAny(EXT_FILTER)) {
if (StringUtils.isNotBlank(sort) && sort.contains(ClientConnectionData.ATTR_INDICATOR_VALUE)) {
final Collection<ClientConnectionData> allConnections = getAllData(filterMap)
.getOrThrow();
@ -155,7 +136,7 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
pageSize,
sort,
allConnections,
pageClientConnectionDataFunction(filterMap, sort));
c -> c.stream().sorted(new IndicatorValueComparator(sort)).collect(Collectors.toList()));
} else {
return this.paginationService.getPage(
@ -227,42 +208,6 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
.collect(Collectors.toList()));
}
private Function<Collection<ClientConnection>, List<ClientConnection>> pageClientConnectionFunction(
final FilterMap filterMap,
final String sort) {
return connections -> {
final List<ClientConnection> filtered = connections
.stream()
.filter(getClientConnectionFilter(filterMap))
.collect(Collectors.toList());
if (StringUtils.isNotBlank(sort)) {
filtered.sort(new ClientConnectionComparator(sort));
}
return filtered;
};
}
private Function<Collection<ClientConnectionData>, List<ClientConnectionData>> pageClientConnectionDataFunction(
final FilterMap filterMap,
final String sort) {
return connections -> {
final List<ClientConnectionData> filtered = connections
.stream()
.filter(getClientConnectionDataFilter(filterMap))
.collect(Collectors.toList());
if (StringUtils.isNotBlank(sort)) {
filtered.sort(new ClientConnectionDataComparator(sort));
}
return filtered;
};
}
private Predicate<ClientConnection> getClientConnectionFilter(final FilterMap filterMap) {
final String infoFilter = filterMap.getString(ClientConnection.FILTER_ATTR_INFO);
Predicate<ClientConnection> filter = Utils.truePredicate();
@ -277,57 +222,25 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
return ccd -> clientConnectionFilter.test(ccd.clientConnection);
}
private static final class ClientConnectionComparator implements Comparator<ClientConnection> {
private static final class IndicatorValueComparator implements Comparator<ClientConnectionData> {
final String sortColumn;
//final ClientConnectionComparator clientConnectionComparator;
final String sort;
final Long iValuePK;
final boolean descending;
ClientConnectionComparator(final String sort) {
this.sortColumn = PageSortOrder.decode(sort);
IndicatorValueComparator(final String sort) {
this.sort = sort;
iValuePK = Long.valueOf(StringUtils.split(sort, Constants.UNDERLINE)[1]);
this.descending = PageSortOrder.getSortOrder(sort) == PageSortOrder.DESCENDING;
}
@Override
public int compare(final ClientConnection cc1, final ClientConnection cc2) {
int result = 0;
if (Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID.equals(this.sortColumn)) {
result = ObjectUtils.compare(cc1.userSessionId, cc2.userSessionId);
} else if (ClientConnection.ATTR_INFO.equals(this.sortColumn)) {
result = ObjectUtils.compare(cc1.getInfo(), cc2.getInfo());
} else if (Domain.CLIENT_CONNECTION.ATTR_STATUS.equals(this.sortColumn)) {
result = ObjectUtils.compare(cc1.getStatus(), cc2.getStatus());
} else {
result = ObjectUtils.compare(cc1.userSessionId, cc2.userSessionId);
}
public int compare(final ClientConnectionData cc1, final ClientConnectionData cc2) {
final Double v1 = cc1.getIndicatorValue(iValuePK);
final Double v2 = cc2.getIndicatorValue(iValuePK);
final int result = ObjectUtils.compare(v1, v2);
return (this.descending) ? -result : result;
}
}
private static final class ClientConnectionDataComparator implements Comparator<ClientConnectionData> {
final ClientConnectionComparator clientConnectionComparator;
ClientConnectionDataComparator(final String sort) {
this.clientConnectionComparator = new ClientConnectionComparator(sort);
}
@Override
public int compare(final ClientConnectionData cc1, final ClientConnectionData cc2) {
if (this.clientConnectionComparator.sortColumn.startsWith(ClientConnectionData.ATTR_INDICATOR_VALUE)) {
try {
final Long iValuePK = Long.valueOf(StringUtils.split(
this.clientConnectionComparator.sortColumn,
Constants.UNDERLINE)[1]);
final Double indicatorValue1 = cc1.getIndicatorValue(iValuePK);
final Double indicatorValue2 = cc2.getIndicatorValue(iValuePK);
final int result = indicatorValue1.compareTo(indicatorValue2);
return (this.clientConnectionComparator.descending) ? -result : result;
} catch (final Exception e) {
return this.clientConnectionComparator.compare(cc1.clientConnection, cc2.clientConnection);
}
}
return this.clientConnectionComparator.compare(cc1.clientConnection, cc2.clientConnection);
}
}
}

View file

@ -122,8 +122,8 @@ public class ExamMonitoringController {
/** This is called by Spring to initialize the WebDataBinder and is used here to
* initialize the default value binding for the institutionId request-parameter
* that has the current users insitutionId as default.
*
* that has the current users institutionId as default.
* <p>
* See also UserService.addUsersInstitutionDefaultPropertySupport */
@InitBinder
public void initBinder(final WebDataBinder binder) {
@ -133,9 +133,9 @@ public class ExamMonitoringController {
}
/** Get a page of all currently running exams
*
* <p>
* GET /{api}/{entity-type-endpoint-name}
*
* <p>
* GET /admin-api/v1/monitoring
* GET /admin-api/v1/monitoring?page_number=2&page_size=10&sort=-name
* GET /admin-api/v1/monitoring?name=seb&active=true
@ -193,9 +193,9 @@ public class ExamMonitoringController {
}
/** Get a page of all currently finished exams
*
* <p>
* GET /{api}/{entity-type-endpoint-name}
*
* <p>
* GET /admin-api/v1/monitoring
* GET /admin-api/v1/monitoring?page_number=2&page_size=10&sort=-name
* GET /admin-api/v1/monitoring?name=seb&active=true
@ -589,13 +589,12 @@ public class ExamMonitoringController {
}
final Set<Long> _filterClientGroups = filterClientGroups;
final Predicate<ClientConnectionData> filter = ccd -> {
return ccd -> {
if (ccd == null) {
return false;
}
return stateFilter.test(ccd) && ccd.filter(_filterClientGroups);
};
return filter;
}
}