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

View file

@ -13,6 +13,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.SqlTable;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -397,6 +398,25 @@ public class PaginationServiceImpl implements PaginationService {
UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord.tableNameAtRuntime(), UserActivityLogRecordDynamicSqlSupport.userActivityLogRecord.tableNameAtRuntime(),
Domain.USER_ACTIVITY_LOG.ATTR_ID); 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) { final Predicate<ClientConnection> predicate) {
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
final QueryExpressionDSL<MyBatis3SelectModelAdapter<List<ClientConnectionRecord>>>.QueryExpressionWhereBuilder whereClause = QueryExpressionDSL<MyBatis3SelectModelAdapter<List<ClientConnectionRecord>>>.QueryExpressionWhereBuilder whereClause =
(filterMap.getBoolean(FilterMap.ATTR_ADD_INSITUTION_JOIN)) (filterMap.getBoolean(FilterMap.ATTR_ADD_INSITUTION_JOIN))
? this.clientConnectionRecordMapper ? this.clientConnectionRecordMapper
.selectByExample() .selectByExample()
@ -130,6 +130,23 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
.where( .where(
ClientConnectionRecordDynamicSqlSupport.institutionId, ClientConnectionRecordDynamicSqlSupport.institutionId,
isEqualToWhenPresent(filterMap.getInstitutionId())); 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 return whereClause
.and( .and(
ClientConnectionRecordDynamicSqlSupport.connectionToken, ClientConnectionRecordDynamicSqlSupport.connectionToken,

View file

@ -8,12 +8,7 @@
package ch.ethz.seb.sebserver.webservice.weblayer.api; package ch.ethz.seb.sebserver.webservice.weblayer.api;
import java.util.Arrays; import java.util.*;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -106,21 +101,7 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
final FilterMap filterMap = new FilterMap(allRequestParams, request.getQueryString()); final FilterMap filterMap = new FilterMap(allRequestParams, request.getQueryString());
populateFilterMap(filterMap, institutionId, sort); populateFilterMap(filterMap, institutionId, sort);
if (StringUtils.isNotBlank(sort) || filterMap.containsAny(EXT_FILTER)) { return super.getPage(institutionId, pageNumber, pageSize, sort, allRequestParams, request);
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);
}
} }
@RequestMapping( @RequestMapping(
@ -145,7 +126,7 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
final FilterMap filterMap = new FilterMap(allRequestParams, request.getQueryString()); final FilterMap filterMap = new FilterMap(allRequestParams, request.getQueryString());
populateFilterMap(filterMap, institutionId, sort); 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) final Collection<ClientConnectionData> allConnections = getAllData(filterMap)
.getOrThrow(); .getOrThrow();
@ -155,7 +136,7 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
pageSize, pageSize,
sort, sort,
allConnections, allConnections,
pageClientConnectionDataFunction(filterMap, sort)); c -> c.stream().sorted(new IndicatorValueComparator(sort)).collect(Collectors.toList()));
} else { } else {
return this.paginationService.getPage( return this.paginationService.getPage(
@ -227,42 +208,6 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
.collect(Collectors.toList())); .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) { private Predicate<ClientConnection> getClientConnectionFilter(final FilterMap filterMap) {
final String infoFilter = filterMap.getString(ClientConnection.FILTER_ATTR_INFO); final String infoFilter = filterMap.getString(ClientConnection.FILTER_ATTR_INFO);
Predicate<ClientConnection> filter = Utils.truePredicate(); Predicate<ClientConnection> filter = Utils.truePredicate();
@ -277,57 +222,25 @@ public class ClientConnectionController extends ReadonlyEntityController<ClientC
return ccd -> clientConnectionFilter.test(ccd.clientConnection); 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; final boolean descending;
ClientConnectionComparator(final String sort) { IndicatorValueComparator(final String sort) {
this.sortColumn = PageSortOrder.decode(sort); this.sort = sort;
iValuePK = Long.valueOf(StringUtils.split(sort, Constants.UNDERLINE)[1]);
this.descending = PageSortOrder.getSortOrder(sort) == PageSortOrder.DESCENDING; this.descending = PageSortOrder.getSortOrder(sort) == PageSortOrder.DESCENDING;
} }
@Override @Override
public int compare(final ClientConnection cc1, final ClientConnection cc2) { public int compare(final ClientConnectionData cc1, final ClientConnectionData cc2) {
int result = 0; final Double v1 = cc1.getIndicatorValue(iValuePK);
if (Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID.equals(this.sortColumn)) { final Double v2 = cc2.getIndicatorValue(iValuePK);
result = ObjectUtils.compare(cc1.userSessionId, cc2.userSessionId); final int result = ObjectUtils.compare(v1, v2);
} 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);
}
return (this.descending) ? -result : result; 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 /** This is called by Spring to initialize the WebDataBinder and is used here to
* initialize the default value binding for the institutionId request-parameter * 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 */ * See also UserService.addUsersInstitutionDefaultPropertySupport */
@InitBinder @InitBinder
public void initBinder(final WebDataBinder binder) { public void initBinder(final WebDataBinder binder) {
@ -133,9 +133,9 @@ public class ExamMonitoringController {
} }
/** Get a page of all currently running exams /** Get a page of all currently running exams
* * <p>
* GET /{api}/{entity-type-endpoint-name} * GET /{api}/{entity-type-endpoint-name}
* * <p>
* GET /admin-api/v1/monitoring * GET /admin-api/v1/monitoring
* GET /admin-api/v1/monitoring?page_number=2&page_size=10&sort=-name * GET /admin-api/v1/monitoring?page_number=2&page_size=10&sort=-name
* GET /admin-api/v1/monitoring?name=seb&active=true * GET /admin-api/v1/monitoring?name=seb&active=true
@ -193,9 +193,9 @@ public class ExamMonitoringController {
} }
/** Get a page of all currently finished exams /** Get a page of all currently finished exams
* * <p>
* GET /{api}/{entity-type-endpoint-name} * GET /{api}/{entity-type-endpoint-name}
* * <p>
* GET /admin-api/v1/monitoring * GET /admin-api/v1/monitoring
* GET /admin-api/v1/monitoring?page_number=2&page_size=10&sort=-name * GET /admin-api/v1/monitoring?page_number=2&page_size=10&sort=-name
* GET /admin-api/v1/monitoring?name=seb&active=true * GET /admin-api/v1/monitoring?name=seb&active=true
@ -589,13 +589,12 @@ public class ExamMonitoringController {
} }
final Set<Long> _filterClientGroups = filterClientGroups; final Set<Long> _filterClientGroups = filterClientGroups;
final Predicate<ClientConnectionData> filter = ccd -> { return ccd -> {
if (ccd == null) { if (ccd == null) {
return false; return false;
} }
return stateFilter.test(ccd) && ccd.filter(_filterClientGroups); return stateFilter.test(ccd) && ccd.filter(_filterClientGroups);
}; };
return filter;
} }
} }