Optimized (memory) /server players table query

This commit is contained in:
Rsl1122 2019-09-15 12:57:40 +03:00
parent 54f98c9fab
commit 2412f5b9d5
9 changed files with 375 additions and 129 deletions

View File

@ -0,0 +1,182 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.delivery.domain;
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
import com.djrapitops.plan.gathering.domain.BaseUser;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
/**
* Represents a player displayed on a player table on players tab or /players page.
*
* @author Rsl1122
*/
public class TablePlayer implements Comparable<TablePlayer> {
private UUID uuid;
private String name;
private ActivityIndex activityIndex;
private Long playtime;
private Integer sessionCount;
private Long registered;
private Long lastSeen;
private String geolocation;
private boolean banned = false;
private TablePlayer() {
}
public static TablePlayer.Builder builder() {
return new TablePlayer.Builder();
}
public static TablePlayer.Builder builderFromBaseUser(BaseUser baseUser) {
return new TablePlayer.Builder()
.uuid(baseUser.getUuid())
.name(baseUser.getName())
.registered(baseUser.getRegistered());
}
public UUID getPlayerUUID() {
return uuid;
}
public Optional<String> getName() {
return Optional.ofNullable(name);
}
public Optional<ActivityIndex> getCurrentActivityIndex() {
return Optional.ofNullable(activityIndex);
}
public Optional<Long> getPlaytime() {
return Optional.ofNullable(playtime);
}
public Optional<Integer> getSessionCount() {
return Optional.ofNullable(sessionCount);
}
public Optional<Long> getRegistered() {
return Optional.ofNullable(registered);
}
public Optional<Long> getLastSeen() {
return Optional.ofNullable(lastSeen);
}
public Optional<String> getGeolocation() {
return Optional.ofNullable(geolocation);
}
public boolean isBanned() {
return banned;
}
@Override
public int compareTo(TablePlayer other) {
// Most recent first
return Long.compare(
other.lastSeen != null ? other.lastSeen : 0L,
this.lastSeen != null ? this.lastSeen : 0L
);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TablePlayer)) return false;
TablePlayer that = (TablePlayer) o;
return playtime == that.playtime &&
sessionCount == that.sessionCount &&
registered == that.registered &&
lastSeen == that.lastSeen &&
name.equals(that.name) &&
activityIndex.equals(that.activityIndex) &&
geolocation.equals(that.geolocation);
}
@Override
public int hashCode() {
return Objects.hash(name, activityIndex, playtime, sessionCount, registered, lastSeen, geolocation);
}
public static class Builder {
private final TablePlayer player;
public Builder() {
player = new TablePlayer();
}
public UUID getPlayerUUID() {
return player.uuid;
}
public Builder uuid(UUID playerUUID) {
player.uuid = playerUUID;
return this;
}
public Builder name(String name) {
player.name = name;
return this;
}
public Builder banned() {
player.banned = true;
return this;
}
public Builder activityIndex(ActivityIndex activityIndex) {
player.activityIndex = activityIndex;
return this;
}
public Builder playtime(long playtime) {
player.playtime = playtime;
return this;
}
public Builder sessionCount(int count) {
player.sessionCount = count;
return this;
}
public Builder registered(long registered) {
player.registered = registered;
return this;
}
public Builder lastSeen(long lastSeen) {
player.lastSeen = lastSeen;
return this;
}
public Builder geolocation(String geolocation) {
player.geolocation = geolocation;
return this;
}
public TablePlayer build() {
return player;
}
}
}

View File

@ -37,8 +37,6 @@ import com.djrapitops.plan.settings.config.paths.TimeSettings;
import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.Database;
import com.djrapitops.plan.storage.database.queries.analysis.PlayerCountQueries;
import com.djrapitops.plan.storage.database.queries.containers.AllPlayerContainersQuery;
import com.djrapitops.plan.storage.database.queries.containers.ServerPlayersTableContainersQuery;
import com.djrapitops.plan.storage.database.queries.objects.*;
import com.djrapitops.plan.utilities.comparators.SessionStartComparator;
@ -84,9 +82,9 @@ public class JSONFactory {
Database database = dbSystem.getDatabase();
return new PlayersTableJSONParser(
database.query(new ServerPlayersTableContainersQuery(serverUUID)),
database.query(new ServerTablePlayersQuery(serverUUID, System.currentTimeMillis(), playtimeThreshold, xMostRecentPlayers)),
database.query(new ExtensionServerPlayerDataTableQuery(serverUUID, xMostRecentPlayers)),
xMostRecentPlayers, playtimeThreshold, openPlayerLinksInNewTab,
openPlayerLinksInNewTab,
formatters
).toJSONString();
}
@ -99,9 +97,9 @@ public class JSONFactory {
Database database = dbSystem.getDatabase();
return new PlayersTableJSONParser(
database.query(new AllPlayerContainersQuery()), // TODO Optimize the heck out of this
Collections.emptyList(),// TODO Replace with new query
Collections.emptyMap(),
xMostRecentPlayers, playtimeThreshold, openPlayerLinksInNewTab,
openPlayerLinksInNewTab,
formatters
).toJSONString();
}

View File

@ -16,11 +16,8 @@
*/
package com.djrapitops.plan.delivery.rendering.json;
import com.djrapitops.plan.delivery.domain.container.PlayerContainer;
import com.djrapitops.plan.delivery.domain.keys.PlayerKeys;
import com.djrapitops.plan.delivery.domain.TablePlayer;
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
import com.djrapitops.plan.delivery.domain.mutators.GeoInfoMutator;
import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator;
import com.djrapitops.plan.delivery.formatting.Formatter;
import com.djrapitops.plan.delivery.formatting.Formatters;
import com.djrapitops.plan.delivery.rendering.html.Html;
@ -29,8 +26,6 @@ import com.djrapitops.plan.delivery.rendering.html.icon.Icon;
import com.djrapitops.plan.extension.FormatType;
import com.djrapitops.plan.extension.icon.Color;
import com.djrapitops.plan.extension.implementation.results.*;
import com.djrapitops.plan.gathering.domain.GeoInfo;
import com.djrapitops.plan.utilities.comparators.PlayerContainerLastPlayedComparator;
import java.util.*;
@ -43,12 +38,10 @@ import java.util.*;
*/
public class PlayersTableJSONParser {
private final List<PlayerContainer> players;
private final List<TablePlayer> players;
private final List<ExtensionDescriptive> extensionDescriptives;
private final Map<UUID, ExtensionTabData> extensionData;
private final int maxPlayers;
private final long activeMsThreshold;
private final boolean openPlayerPageInNewTab;
private Map<FormatType, Formatter<Long>> numberFormatters;
@ -57,10 +50,10 @@ public class PlayersTableJSONParser {
public PlayersTableJSONParser(
// Data
List<PlayerContainer> players,
List<TablePlayer> players,
Map<UUID, ExtensionTabData> extensionData,
// Settings
int maxPlayers, long activeMsThreshold, boolean openPlayerPageInNewTab,
boolean openPlayerPageInNewTab,
// Formatters
Formatters formatters
) {
@ -73,8 +66,6 @@ public class PlayersTableJSONParser {
extensionDescriptives.sort((one, two) -> String.CASE_INSENSITIVE_ORDER.compare(one.getName(), two.getName()));
// Settings
this.maxPlayers = maxPlayers;
this.activeMsThreshold = activeMsThreshold;
this.openPlayerPageInNewTab = openPlayerPageInNewTab;
// Formatters
numberFormatters = new EnumMap<>(FormatType.class);
@ -107,15 +98,9 @@ public class PlayersTableJSONParser {
private String parseData() {
StringBuilder dataJSON = new StringBuilder("[");
long now = System.currentTimeMillis();
players.sort(new PlayerContainerLastPlayedComparator());
int currentPlayerNumber = 0;
for (PlayerContainer player : players) {
if (currentPlayerNumber >= maxPlayers) {
break;
}
UUID playerUUID = player.getValue(PlayerKeys.UUID).orElse(null);
for (TablePlayer player : players) {
UUID playerUUID = player.getPlayerUUID();
if (playerUUID == null) {
continue;
}
@ -125,7 +110,7 @@ public class PlayersTableJSONParser {
}
dataJSON.append('{'); // Start new item
appendPlayerData(dataJSON, now, player);
appendPlayerData(dataJSON, player);
appendExtensionData(dataJSON, extensionData.getOrDefault(playerUUID, new ExtensionTabData.Factory(null).build()));
dataJSON.append('}'); // Close new item
@ -135,22 +120,21 @@ public class PlayersTableJSONParser {
return dataJSON.append(']').toString();
}
private void appendPlayerData(StringBuilder dataJSON, long now, PlayerContainer player) {
String name = player.getValue(PlayerKeys.NAME).orElse("Unknown");
private void appendPlayerData(StringBuilder dataJSON, TablePlayer player) {
String name = player.getName().orElse(player.getPlayerUUID().toString());
String url = "../player/" + name;
SessionsMutator sessionsMutator = SessionsMutator.forContainer(player);
int loginTimes = sessionsMutator.count();
long playtime = sessionsMutator.toPlaytime();
long registered = player.getValue(PlayerKeys.REGISTERED).orElse(0L);
long lastSeen = sessionsMutator.toLastSeen();
int loginTimes = player.getSessionCount().orElse(0);
long playtime = player.getPlaytime().orElse(-1L);
long registered = player.getRegistered().orElse(-1L);
long lastSeen = player.getLastSeen().orElse(-1L);
ActivityIndex activityIndex = player.getActivityIndex(now, activeMsThreshold);
boolean isBanned = player.getValue(PlayerKeys.BANNED).orElse(false);
ActivityIndex activityIndex = player.getCurrentActivityIndex().orElseGet(() -> new ActivityIndex(0.0, 0));
boolean isBanned = player.isBanned();
String activityString = activityIndex.getFormattedValue(decimalFormatter)
+ (isBanned ? " (<b>Banned</b>)" : " (" + activityIndex.getGroup() + ")");
String geolocation = GeoInfoMutator.forContainer(player).mostRecent().map(GeoInfo::getGeolocation).orElse("-");
String geolocation = player.getGeolocation().orElse("-");
Html link = openPlayerPageInNewTab ? Html.LINK_EXTERNAL : Html.LINK;

View File

@ -112,7 +112,7 @@ public class WorldAliasSettings {
String worldName = entry.getKey();
long playtime = entry.getValue();
if (!aliases.contains(worldName)) {
if (worldName != null && !aliases.contains(worldName)) {
addWorld(worldName);
}

View File

@ -27,6 +27,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import static com.djrapitops.plan.storage.database.sql.parsing.Sql.*;
@ -72,7 +73,7 @@ public class ActivityIndexQueries {
return fetchActivityGroupCount(date, serverUUID, playtimeThreshold, ActivityIndex.REGULAR, 5.1);
}
private static String selectActivityIndexSQL() {
public static String selectActivityIndexSQL() {
String selectActivePlaytimeSQL = SELECT +
SessionsTable.USER_UUID +
",SUM(" +
@ -93,7 +94,7 @@ public class ActivityIndexQueries {
GROUP_BY + "q1." + SessionsTable.USER_UUID;
}
private static void setSelectActivityIndexSQLParameters(PreparedStatement statement, int index, long playtimeThreshold, UUID serverUUID, long date) throws SQLException {
public static void setSelectActivityIndexSQLParameters(PreparedStatement statement, int index, long playtimeThreshold, UUID serverUUID, long date) throws SQLException {
statement.setDouble(index, Math.PI);
statement.setLong(index + 1, playtimeThreshold);
@ -477,4 +478,28 @@ public class ActivityIndexQueries {
}
};
}
public static Query<Object> activityIndexOnServerToMap(UUID serverUUID, long date, long threshold, BiConsumer<UUID, Double> consumer) {
String sql = SELECT + "activity_index,n." + UserInfoTable.USER_UUID +
FROM + UserInfoTable.TABLE_NAME + " n" +
LEFT_JOIN + '(' + selectActivityIndexSQL() + ") a on n." + SessionsTable.USER_UUID + "=a." + UserInfoTable.USER_UUID +
WHERE + UserInfoTable.SERVER_UUID + "=?";
return new QueryStatement<Object>(sql, 1000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
setSelectActivityIndexSQLParameters(statement, 1, threshold, serverUUID, date);
statement.setString(2, serverUUID.toString());
}
@Override
public Object processResults(ResultSet set) throws SQLException {
while (set.next()) {
double activityIndex = set.getDouble("activity_index"); // Returns 0.0 if missing
consumer.accept(UUID.fromString(set.getString(UserInfoTable.USER_UUID)), activityIndex);
}
return null;
}
};
}
}

View File

@ -1,85 +0,0 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.storage.database.queries.containers;
import com.djrapitops.plan.delivery.domain.container.PlayerContainer;
import com.djrapitops.plan.delivery.domain.keys.PlayerKeys;
import com.djrapitops.plan.delivery.domain.mutators.SessionsMutator;
import com.djrapitops.plan.gathering.domain.BaseUser;
import com.djrapitops.plan.gathering.domain.GeoInfo;
import com.djrapitops.plan.gathering.domain.Session;
import com.djrapitops.plan.storage.database.SQLDB;
import com.djrapitops.plan.storage.database.queries.Query;
import com.djrapitops.plan.storage.database.queries.objects.BaseUserQueries;
import com.djrapitops.plan.storage.database.queries.objects.GeoInfoQueries;
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries;
import java.util.*;
/**
* Optimized version of {@link ServerPlayerContainersQuery} for /server page Players table.
*
* @author Rsl1122
* @see com.djrapitops.plan.delivery.rendering.json.PlayersTableJSONParser For what needs to be included.
*/
public class ServerPlayersTableContainersQuery implements Query<List<PlayerContainer>> {
private final UUID serverUUID;
public ServerPlayersTableContainersQuery(UUID serverUUID) {
this.serverUUID = serverUUID;
}
@Override
public List<PlayerContainer> executeQuery(SQLDB db) {
List<PlayerContainer> containers = new ArrayList<>();
Collection<BaseUser> baseUsers = db.query(BaseUserQueries.fetchServerBaseUsers(serverUUID));
Map<UUID, List<GeoInfo>> geoInformation = db.query(GeoInfoQueries.fetchServerGeoInformation(serverUUID));
// TODO Optimize the heck out of this
Map<UUID, List<Session>> sessions = db.query(SessionQueries.fetchSessionsOfServer(serverUUID));
Set<UUID> bannedUsers = db.query(UserInfoQueries.fetchBannedUUIDsOfServer(serverUUID));
for (BaseUser user : baseUsers) {
PlayerContainer container = new PlayerContainer();
// BaseUser
UUID uuid = user.getUuid();
container.putRawData(PlayerKeys.UUID, uuid);
container.putRawData(PlayerKeys.NAME, user.getName());
container.putRawData(PlayerKeys.REGISTERED, user.getRegistered());
container.putRawData(PlayerKeys.BANNED, bannedUsers.contains(uuid));
// GeoInfo
container.putRawData(PlayerKeys.GEO_INFO, geoInformation.getOrDefault(uuid, new ArrayList<>()));
container.putCachingSupplier(PlayerKeys.SESSIONS, () -> {
List<Session> playerSessions = sessions.getOrDefault(uuid, new ArrayList<>());
container.getValue(PlayerKeys.ACTIVE_SESSION).ifPresent(playerSessions::add);
return playerSessions;
}
);
container.putCachingSupplier(PlayerKeys.LAST_SEEN, () -> SessionsMutator.forContainer(container).toLastSeen());
containers.add(container);
}
return containers;
}
}

View File

@ -0,0 +1,134 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.storage.database.queries.objects;
import com.djrapitops.plan.delivery.domain.TablePlayer;
import com.djrapitops.plan.delivery.domain.mutators.ActivityIndex;
import com.djrapitops.plan.storage.database.SQLDB;
import com.djrapitops.plan.storage.database.queries.Query;
import com.djrapitops.plan.storage.database.queries.QueryStatement;
import com.djrapitops.plan.storage.database.queries.analysis.ActivityIndexQueries;
import com.djrapitops.plan.storage.database.sql.tables.GeoInfoTable;
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
import com.djrapitops.plan.storage.database.sql.tables.UserInfoTable;
import com.djrapitops.plan.storage.database.sql.tables.UsersTable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static com.djrapitops.plan.storage.database.sql.parsing.Sql.*;
/**
* Query for displaying players on /server page players tab.
*
* @author Rsl1122
*/
public class ServerTablePlayersQuery implements Query<List<TablePlayer>> {
private final UUID serverUUID;
private final long date;
private final long activeMsThreshold;
private final int xMostRecentPlayers;
public ServerTablePlayersQuery(UUID serverUUID, long date, long activeMsThreshold, int xMostRecentPlayers) {
this.serverUUID = serverUUID;
this.date = date;
this.activeMsThreshold = activeMsThreshold;
this.xMostRecentPlayers = xMostRecentPlayers;
}
@Override
public List<TablePlayer> executeQuery(SQLDB db) {
String selectGeolocations = SELECT +
GeoInfoTable.USER_UUID + ", " +
GeoInfoTable.GEOLOCATION + ", " +
GeoInfoTable.LAST_USED +
FROM + GeoInfoTable.TABLE_NAME;
String selectLatestGeolocationDate = SELECT +
GeoInfoTable.USER_UUID + ", " +
"MAX(" + GeoInfoTable.LAST_USED + ") as last_used_g" +
FROM + GeoInfoTable.TABLE_NAME +
GROUP_BY + GeoInfoTable.USER_UUID;
String selectLatestGeolocations = SELECT +
"g1." + GeoInfoTable.GEOLOCATION + ',' +
"g1." + GeoInfoTable.USER_UUID +
FROM + "(" + selectGeolocations + ") AS g1" +
INNER_JOIN + "(" + selectLatestGeolocationDate + ") AS g2 ON g1.uuid = g2.uuid" +
WHERE + GeoInfoTable.LAST_USED + "=last_used_g";
String selectSessionData = SELECT + "s." + SessionsTable.USER_UUID + ',' +
"MAX(" + SessionsTable.SESSION_END + ") as last_seen," +
"COUNT(1) as count," +
"SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + ") as playtime" +
FROM + SessionsTable.TABLE_NAME + " s" +
WHERE + "s." + SessionsTable.SERVER_UUID + "=?" +
GROUP_BY + "s." + SessionsTable.USER_UUID;
String selectBaseUsers = SELECT +
"u." + UsersTable.USER_UUID + ',' +
"u." + UsersTable.USER_NAME + ',' +
"u." + UsersTable.REGISTERED + ',' +
UserInfoTable.BANNED + ',' +
"geoloc." + GeoInfoTable.GEOLOCATION + ',' +
"ses.last_seen," +
"ses.count," +
"ses.playtime," +
"act.activity_index" +
FROM + UsersTable.TABLE_NAME + " u" +
INNER_JOIN + UserInfoTable.TABLE_NAME + " on u." + UsersTable.USER_UUID + "=" + UserInfoTable.TABLE_NAME + '.' + UserInfoTable.USER_UUID +
LEFT_JOIN + '(' + selectLatestGeolocations + ") geoloc on geoloc." + GeoInfoTable.USER_UUID + "=u." + UsersTable.USER_UUID +
LEFT_JOIN + '(' + selectSessionData + ") ses on ses." + SessionsTable.USER_UUID + "=u." + UsersTable.USER_UUID +
LEFT_JOIN + '(' + ActivityIndexQueries.selectActivityIndexSQL() + ") act on u." + SessionsTable.USER_UUID + "=act." + UserInfoTable.USER_UUID +
WHERE + UserInfoTable.SERVER_UUID + "=?" +
ORDER_BY + "ses.last_seen DESC LIMIT ?";
return db.query(new QueryStatement<List<TablePlayer>>(selectBaseUsers, 1000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, serverUUID.toString()); // Session query
ActivityIndexQueries.setSelectActivityIndexSQLParameters(statement, 2, activeMsThreshold, serverUUID, date);
statement.setString(13, serverUUID.toString()); // Session query
statement.setInt(14, xMostRecentPlayers);
}
@Override
public List<TablePlayer> processResults(ResultSet set) throws SQLException {
List<TablePlayer> players = new ArrayList<>();
while (set.next()) {
TablePlayer.Builder player = TablePlayer.builder()
.uuid(UUID.fromString(set.getString(UsersTable.USER_UUID)))
.name(set.getString(UsersTable.USER_NAME))
.geolocation(set.getString(GeoInfoTable.GEOLOCATION))
.registered(set.getLong(UsersTable.REGISTERED))
.lastSeen(set.getLong("last_seen"))
.sessionCount(set.getInt("count"))
.playtime(set.getLong("playtime"))
.activityIndex(new ActivityIndex(set.getDouble("activity_index"), date));
if (set.getBoolean(UserInfoTable.BANNED)) {
player.banned();
}
players.add(player.build());
}
return players;
}
});
}
}

View File

@ -29,7 +29,6 @@ import com.djrapitops.plan.storage.database.queries.QueryStatement;
import com.djrapitops.plan.storage.database.sql.parsing.Sql;
import com.djrapitops.plan.storage.database.sql.tables.*;
import com.djrapitops.plan.utilities.comparators.DateHolderRecentComparator;
import com.djrapitops.plan.utilities.comparators.SessionStartComparator;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -263,7 +262,7 @@ public class SessionQueries {
.flatMap(Collection::stream)
.map(SortedMap::values)
.flatMap(Collection::stream)
.sorted(new SessionStartComparator()) // Disorder arises
.sorted(dateColderRecentComparator) // Disorder arises
.collect(Collectors.toList());
}

View File

@ -20,6 +20,7 @@ import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.data.element.TableContainer;
import com.djrapitops.plan.delivery.domain.DateObj;
import com.djrapitops.plan.delivery.domain.Nickname;
import com.djrapitops.plan.delivery.domain.TablePlayer;
import com.djrapitops.plan.delivery.domain.WebUser;
import com.djrapitops.plan.delivery.domain.container.PlayerContainer;
import com.djrapitops.plan.delivery.domain.container.ServerContainer;
@ -1406,7 +1407,7 @@ public interface DatabaseTest {
}
@Test
default void activeTunredInactiveQueryHasAllParametersSet() {
default void activeTurnedInactiveQueryHasAllParametersSet() {
Integer result = db().query(ActivityIndexQueries.countRegularPlayersTurnedInactive(
0, System.currentTimeMillis(), serverUUID(),
TimeUnit.HOURS.toMillis(2L)
@ -1414,6 +1415,14 @@ public interface DatabaseTest {
assertNotNull(result);
}
@Test
default void serverTablePlayersQueryQueriesAtLeastOnePlayer() {
sessionsAreStoredWithAllData();
List<TablePlayer> result = db().query(new ServerTablePlayersQuery(serverUUID(), System.currentTimeMillis(), 10L, 1));
assertNotEquals(Collections.emptyList(), result);
}
@PluginInfo(name = "ConditionalExtension")
class ConditionalExtension implements DataExtension {