LargeStoreQueries now stores missing world names as well.

Affects issues:
- Fixed #1848
This commit is contained in:
Risto Lahtela 2021-04-18 09:23:09 +03:00
parent acf15a1e86
commit 599bf4a837
4 changed files with 147 additions and 7 deletions

View File

@ -0,0 +1,64 @@
/*
* 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.identification.ServerUUID;
import java.util.Objects;
/**
* Represents a world stored in the Plan database.
*/
public class World {
private final String worldName;
private final ServerUUID serverUUID;
public World(String worldName, ServerUUID serverUUID) {
this.worldName = worldName;
this.serverUUID = serverUUID;
}
public String getWorldName() {
return worldName;
}
public ServerUUID getServerUUID() {
return serverUUID;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
World world = (World) o;
return Objects.equals(getWorldName(), world.getWorldName()) && Objects.equals(getServerUUID(), world.getServerUUID());
}
@Override
public int hashCode() {
return Objects.hash(getWorldName(), getServerUUID());
}
@Override
public String toString() {
return "World{" +
"worldName='" + worldName + '\'' +
", serverUUID=" + serverUUID +
'}';
}
}

View File

@ -17,10 +17,12 @@
package com.djrapitops.plan.storage.database.queries;
import com.djrapitops.plan.delivery.domain.Nickname;
import com.djrapitops.plan.delivery.domain.World;
import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.gathering.domain.*;
import com.djrapitops.plan.identification.Server;
import com.djrapitops.plan.identification.ServerUUID;
import com.djrapitops.plan.storage.database.queries.objects.WorldTimesQueries;
import com.djrapitops.plan.storage.database.sql.tables.*;
import com.djrapitops.plan.storage.database.transactions.ExecBatchStatement;
import com.djrapitops.plan.storage.database.transactions.Executable;
@ -29,10 +31,8 @@ import org.apache.commons.lang3.StringUtils;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
/**
* Static method class for large storage queries.
@ -292,12 +292,40 @@ public class LargeStoreQueries {
public static Executable storeAllSessionsWithKillAndWorldData(Collection<FinishedSession> sessions) {
return connection -> {
Set<World> existingWorlds = WorldTimesQueries.fetchWorlds().executeWithConnection(connection);
storeAllWorldNames(sessions, existingWorlds).execute(connection);
storeAllSessionsWithoutKillOrWorldData(sessions).execute(connection);
storeSessionKillData(sessions).execute(connection);
return storeSessionWorldTimeData(sessions).execute(connection);
};
}
private static Executable storeAllWorldNames(Collection<FinishedSession> sessions, Set<World> existingWorlds) {
Set<World> worlds = sessions.stream().flatMap(session -> {
ServerUUID serverUUID = session.getServerUUID();
return session.getExtraData(WorldTimes.class)
.map(WorldTimes::getWorldTimes)
.map(Map::keySet)
.orElseGet(Collections::emptySet)
.stream()
.map(worldName -> new World(worldName, serverUUID));
}).filter(world -> !existingWorlds.contains(world))
.collect(Collectors.toSet());
if (worlds.isEmpty()) return Executable.empty();
return new ExecBatchStatement(WorldTable.INSERT_STATEMENT) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
for (World world : worlds) {
statement.setString(1, world.getWorldName());
statement.setString(2, world.getServerUUID().toString());
statement.addBatch();
}
}
};
}
private static Executable storeSessionKillData(Collection<FinishedSession> sessions) {
if (sessions == null || sessions.isEmpty()) return Executable.empty();

View File

@ -16,10 +16,12 @@
*/
package com.djrapitops.plan.storage.database.queries.objects;
import com.djrapitops.plan.delivery.domain.World;
import com.djrapitops.plan.gathering.domain.GMTimes;
import com.djrapitops.plan.gathering.domain.WorldTimes;
import com.djrapitops.plan.identification.ServerUUID;
import com.djrapitops.plan.storage.database.queries.Query;
import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
import com.djrapitops.plan.storage.database.queries.QueryStatement;
import com.djrapitops.plan.storage.database.sql.tables.SessionsTable;
import com.djrapitops.plan.storage.database.sql.tables.WorldTable;
@ -28,9 +30,7 @@ import com.djrapitops.plan.storage.database.sql.tables.WorldTimesTable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
@ -198,4 +198,21 @@ public class WorldTimesQueries {
}
};
}
public static QueryStatement<Set<World>> fetchWorlds() {
String worldNameSql = SELECT + '*' + FROM + WorldTable.TABLE_NAME;
return new QueryAllStatement<Set<World>>(worldNameSql) {
@Override
public Set<World> processResults(ResultSet set) throws SQLException {
Set<World> worlds = new HashSet<>();
while (set.next()) {
worlds.add(new World(
set.getString(WorldTable.NAME),
ServerUUID.fromString(set.getString(WorldTable.SERVER_UUID))
));
}
return worlds;
}
};
}
}

View File

@ -31,6 +31,8 @@ import com.djrapitops.plan.storage.database.queries.objects.KillQueries;
import com.djrapitops.plan.storage.database.queries.objects.SessionQueries;
import com.djrapitops.plan.storage.database.queries.objects.WorldTimesQueries;
import com.djrapitops.plan.storage.database.queries.objects.playertable.ServerTablePlayersQuery;
import com.djrapitops.plan.storage.database.sql.tables.WorldTable;
import com.djrapitops.plan.storage.database.transactions.ExecStatement;
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
import com.djrapitops.plan.storage.database.transactions.Transaction;
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction;
@ -43,6 +45,7 @@ import org.junit.jupiter.api.Test;
import utilities.RandomData;
import utilities.TestConstants;
import java.sql.PreparedStatement;
import java.util.*;
import java.util.concurrent.TimeUnit;
@ -152,6 +155,34 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
assertEquals(worldTimes, allSessions.get(0).getExtraData(WorldTimes.class).get());
}
@Test
default void worldTimesAreSavedWithSessionWithoutWorlds() {
prepareForSessionSave();
// Remove the worlds from the database so that they need to also be saved.
execute(new ExecStatement("DELETE FROM " + WorldTable.TABLE_NAME) {
@Override
public void prepare(PreparedStatement statement) {
// Nothing needed
}
});
WorldTimes worldTimes = RandomData.randomWorldTimes(worlds);
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID);
session.getExtraData().put(WorldTimes.class, worldTimes);
List<FinishedSession> sessions = new ArrayList<>();
sessions.add(session);
db().executeTransaction(new Transaction() {
@Override
protected void performOperations() {
execute(LargeStoreQueries.storeAllSessionsWithKillAndWorldData(sessions));
}
});
List<FinishedSession> allSessions = db().query(SessionQueries.fetchAllSessions());
assertEquals(worldTimes, allSessions.get(0).getExtraData(WorldTimes.class).get());
}
@Test
default void playersWorldTimesMatchTotal() {
worldTimesAreSavedWithSession();