mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-01-13 19:51:25 +01:00
Begun work on the data refactoring, long way to go.
This commit is contained in:
parent
2af36b0ec8
commit
8f474c37f6
@ -0,0 +1,17 @@
|
||||
package com.djrapitops.plan.api.exceptions.database;
|
||||
|
||||
/**
|
||||
* Runtime exception for wrapping database errors.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DBOpException extends RuntimeException {
|
||||
|
||||
public DBOpException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DBOpException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
package com.djrapitops.plan.data.container;
|
||||
|
||||
import com.djrapitops.plan.data.store.objects.DateMap;
|
||||
import com.djrapitops.plan.utilities.FormatUtils;
|
||||
import com.djrapitops.plan.utilities.SHA256Hash;
|
||||
import com.google.common.base.Objects;
|
||||
@ -35,6 +36,14 @@ public class GeoInfo {
|
||||
this.ipHash = ipHash;
|
||||
}
|
||||
|
||||
public static DateMap<GeoInfo> intoDateMap(Iterable<GeoInfo> geoInfo) {
|
||||
DateMap<GeoInfo> map = new DateMap<>();
|
||||
for (GeoInfo info : geoInfo) {
|
||||
map.put(info.lastUsed, info);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package com.djrapitops.plan.data.store;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Caching layer between Supplier and caller.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class CachingSupplier<T> implements Supplier<T> {
|
||||
|
||||
private final Supplier<T> original;
|
||||
private T cachedValue;
|
||||
|
||||
public CachingSupplier(Supplier<T> original) {
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
if (cachedValue == null) {
|
||||
cachedValue = original.get();
|
||||
}
|
||||
return cachedValue;
|
||||
}
|
||||
}
|
68
Plan/src/main/java/com/djrapitops/plan/data/store/Key.java
Normal file
68
Plan/src/main/java/com/djrapitops/plan/data/store/Key.java
Normal file
@ -0,0 +1,68 @@
|
||||
package com.djrapitops.plan.data.store;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Identifier used for storing and fetching data from DataContainers.
|
||||
*
|
||||
* @param <T> Type of the object returned by the Value identified by this Key.
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class Key<T> {
|
||||
|
||||
private final Type<T> type;
|
||||
private final String keyName;
|
||||
|
||||
/**
|
||||
* Create a new key.
|
||||
* <p>
|
||||
* Example usage:
|
||||
* {@code Key<String> key = new Key(String.class, "identifier");}
|
||||
* <p>
|
||||
* (In Keys class) {@code public static final Key<String> IDENTIFIER = new Key(String.class, "identifier");}
|
||||
* {@code Key<String> key = Keys.IDENTIFIER;}
|
||||
*
|
||||
* @param type Class with type of the Object returned by the Value identified by this Key.
|
||||
* @param keyName Name (identifier) of the Key.
|
||||
*/
|
||||
public Key(Class<T> type, String keyName) {
|
||||
this(Type.ofClass(type), keyName);
|
||||
}
|
||||
|
||||
public Key(Type<T> type, String keyName) {
|
||||
this.type = type;
|
||||
this.keyName = keyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of the key.
|
||||
*
|
||||
* @return specified in constructor.
|
||||
*/
|
||||
public Type<T> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name (identifier) of the Key.
|
||||
*
|
||||
* @return For example "nickname"
|
||||
*/
|
||||
public String getKeyName() {
|
||||
return keyName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Key<?> key = (Key<?>) o;
|
||||
return Objects.equals(type, key.type) &&
|
||||
Objects.equals(keyName, key.keyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, keyName);
|
||||
}
|
||||
}
|
20
Plan/src/main/java/com/djrapitops/plan/data/store/Type.java
Normal file
20
Plan/src/main/java/com/djrapitops/plan/data/store/Type.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.djrapitops.plan.data.store;
|
||||
|
||||
/**
|
||||
* Similar to Google's TypeToken but without requiring whole gson package.
|
||||
* <p>
|
||||
* Create new instance with {@code new Type<YourObject>() {}}.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public abstract class Type<T> {
|
||||
|
||||
public static <K> Type<K> ofClass(Class<K> of) {
|
||||
return new Type<K>() {};
|
||||
}
|
||||
|
||||
public static <K> Type<K> of(K object) {
|
||||
return new Type<K>() {};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.djrapitops.plan.data.store.containers;
|
||||
|
||||
import com.djrapitops.plan.data.store.CachingSupplier;
|
||||
import com.djrapitops.plan.data.store.Key;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Abstract representation of an object that holds the Values for different Keys.
|
||||
* <p>
|
||||
* The methods in this object are used for placing and fetching the data from the container.
|
||||
* Methods to use depend on your use case.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DataContainer extends HashMap<Key, Supplier> {
|
||||
|
||||
/**
|
||||
* Place your data inside the container.
|
||||
*
|
||||
* @param key Key of type T that identifies the data and will be used later when the data needs to be fetched.
|
||||
* @param obj object to store
|
||||
* @param <T> Type of the object
|
||||
*/
|
||||
public <T> void putRawData(Key<T> key, T obj) {
|
||||
put(key, () -> obj);
|
||||
}
|
||||
|
||||
public <T> void putSupplier(Key<T> key, Supplier<T> supplier) {
|
||||
put(key, new CachingSupplier<>(supplier));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a Value with the given Key has been placed into the container.
|
||||
*
|
||||
* @param key Key that identifies the data.
|
||||
* @param <T> Type of the object returned by the Value if it is present.
|
||||
* @return true if found, false if not.
|
||||
*/
|
||||
public <T> boolean supports(Key<T> key) {
|
||||
return containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an Optional of the data identified by the Key.
|
||||
* <p>
|
||||
* Since Value is a functional interface, its method may call blocking methods via Value implementations,
|
||||
* It is therefore recommended to not call this method on the server thread.
|
||||
* <p>
|
||||
* It is recommended to check if the Optional is present as null values returned by plugins will be empty.
|
||||
*
|
||||
* @param key Key that identifies the Value
|
||||
* @param <T> Type of the object returned by Value
|
||||
* @return Optional of the object if the key is registered and key matches the type of the object. Otherwise empty.
|
||||
*/
|
||||
public <T> Optional<T> getValue(Key<T> key) {
|
||||
Supplier supplier = get(key);
|
||||
if (supplier == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
return Optional.of((T) supplier.get());
|
||||
} catch (ClassCastException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T getUnsafe(Key<T> key) {
|
||||
Supplier supplier = get(key);
|
||||
if (supplier == null) {
|
||||
throw new IllegalArgumentException("Unsupported Key");
|
||||
}
|
||||
return (T) supplier.get();
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.djrapitops.plan.data.store.containers;
|
||||
|
||||
/**
|
||||
* DataContainer about a Player.
|
||||
* <p>
|
||||
* Use {@code getValue(PlayerKeys.REGISTERED).isPresent()} to determine if Plan has data about the player.
|
||||
*
|
||||
* @author Rsl1122
|
||||
* @see com.djrapitops.plan.data.store.keys.PlayerKeys for supported Key objects.
|
||||
*/
|
||||
public class PlayerContainer extends DataContainer {
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.djrapitops.plan.data.store.keys;
|
||||
|
||||
import com.djrapitops.plan.data.store.Key;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Class holding Key objects that are commonly used across multiple DataContainers.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class CommonKeys {
|
||||
|
||||
public static final Key<UUID> UUID = new Key<>(UUID.class, "uuid");
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.djrapitops.plan.data.store.keys;
|
||||
|
||||
import com.djrapitops.plan.data.container.GeoInfo;
|
||||
import com.djrapitops.plan.data.store.Key;
|
||||
import com.djrapitops.plan.data.store.Type;
|
||||
import com.djrapitops.plan.data.store.objects.DateMap;
|
||||
import com.djrapitops.plan.data.store.objects.Nickname;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Class that holds Key objects for PlayerContainer.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlayerKeys {
|
||||
|
||||
public static final Key<UUID> UUID = CommonKeys.UUID;
|
||||
public static final Key<String> NAME = new Key<>(String.class, "name");
|
||||
public static final Key<List<Nickname>> NICKNAMES = new Key<>(new Type<List<Nickname>>() {}, "nicknames");
|
||||
|
||||
public static final Key<Long> REGISTERED = new Key<>(Long.class, "registered");
|
||||
|
||||
public static final Key<DateMap<UUID>> KICKS = new Key<>(new Type<DateMap<UUID>>() {}, "kicks");
|
||||
public static final Key<DateMap<GeoInfo>> GEO_INFO = new Key<>(new Type<DateMap<GeoInfo>>() {}, "geo_info");
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.djrapitops.plan.data.store.objects;
|
||||
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Basic TreeMap that uses Epoch MS as keys.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DateMap<T> extends TreeMap<Long, T> {
|
||||
|
||||
public DateMap() {
|
||||
super(Long::compareTo);
|
||||
}
|
||||
|
||||
public boolean hasValuesBetween(long after, long before) {
|
||||
return countBetween(after, before) > 0;
|
||||
}
|
||||
|
||||
public int countBetween(long after, long before) {
|
||||
return subMap(after, before).size();
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.djrapitops.plan.data.store.objects;
|
||||
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Basic TreeSet with Epoch ms as values.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class DateSet extends TreeSet<Long> {
|
||||
|
||||
public boolean hasValuesBetween(long after, long before) {
|
||||
return countBetween(after, before) > 0;
|
||||
}
|
||||
|
||||
public int countBetween(long after, long before) {
|
||||
return subSet(after, before).size();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.djrapitops.plan.data.store.objects;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Object storing nickname information.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class Nickname {
|
||||
|
||||
private final String name;
|
||||
private final long lastUsed;
|
||||
private final UUID serverUUID;
|
||||
|
||||
public Nickname(String name, long lastUsed, UUID serverUUID) {
|
||||
this.name = name;
|
||||
this.lastUsed = lastUsed;
|
||||
this.serverUUID = serverUUID;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public long getLastUsed() {
|
||||
return lastUsed;
|
||||
}
|
||||
|
||||
public UUID getServerUUID() {
|
||||
return serverUUID;
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.djrapitops.plan.data.store.objects;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Map object that has ServerUUID as keys.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PerServer<T> extends HashMap<UUID, T> {
|
||||
|
||||
}
|
@ -5,6 +5,7 @@ import com.djrapitops.plan.data.PlayerProfile;
|
||||
import com.djrapitops.plan.data.ServerProfile;
|
||||
import com.djrapitops.plan.data.WebUser;
|
||||
import com.djrapitops.plan.data.container.*;
|
||||
import com.djrapitops.plan.data.store.containers.PlayerContainer;
|
||||
import com.djrapitops.plan.system.info.server.Server;
|
||||
|
||||
import java.util.*;
|
||||
@ -21,6 +22,8 @@ public interface FetchOperations {
|
||||
|
||||
// UUIDs
|
||||
|
||||
PlayerContainer getPlayerContainer(UUID uuid);
|
||||
|
||||
Set<UUID> getSavedUUIDs() throws DBException;
|
||||
|
||||
Set<UUID> getSavedUUIDs(UUID server) throws DBException;
|
||||
|
@ -1,10 +1,13 @@
|
||||
package com.djrapitops.plan.system.database.databases.sql.operation;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.data.PlayerProfile;
|
||||
import com.djrapitops.plan.data.ServerProfile;
|
||||
import com.djrapitops.plan.data.WebUser;
|
||||
import com.djrapitops.plan.data.container.*;
|
||||
import com.djrapitops.plan.data.store.containers.PlayerContainer;
|
||||
import com.djrapitops.plan.data.store.keys.PlayerKeys;
|
||||
import com.djrapitops.plan.system.database.databases.operation.FetchOperations;
|
||||
import com.djrapitops.plan.system.database.databases.sql.SQLDB;
|
||||
import com.djrapitops.plan.system.info.server.Server;
|
||||
@ -116,9 +119,22 @@ public class SQLFetchOps extends SQLOps implements FetchOperations {
|
||||
return profile;
|
||||
} catch (SQLException e) {
|
||||
throw SQLErrorUtil.getExceptionFor(e);
|
||||
} catch (DBOpException e) {
|
||||
throw new DBException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerContainer getPlayerContainer(UUID uuid) {
|
||||
PlayerContainer container = new PlayerContainer();
|
||||
container.putRawData(PlayerKeys.UUID, uuid);
|
||||
|
||||
container.putAll(usersTable.getUserInformation(uuid));
|
||||
|
||||
container.put(PlayerKeys.GEO_INFO, () -> GeoInfo.intoDateMap(geoInfoTable.getGeoInfo(uuid)));
|
||||
return container;
|
||||
}
|
||||
|
||||
private void addUserInfoToProfile(PlayerProfile profile, Map<UUID, UserInfo> userInfo) {
|
||||
for (Map.Entry<UUID, UserInfo> entry : userInfo.entrySet()) {
|
||||
UUID serverUUID = entry.getKey();
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.djrapitops.plan.system.database.databases.sql.tables;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.data.container.GeoInfo;
|
||||
import com.djrapitops.plan.system.database.databases.sql.SQLDB;
|
||||
import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement;
|
||||
@ -129,29 +130,33 @@ public class GeoInfoTable extends UserIDTable {
|
||||
|
||||
}
|
||||
|
||||
public List<GeoInfo> getGeoInfo(UUID uuid) throws SQLException {
|
||||
public List<GeoInfo> getGeoInfo(UUID uuid) {
|
||||
String sql = "SELECT DISTINCT * FROM " + tableName +
|
||||
" WHERE " + Col.USER_ID + "=" + usersTable.statementSelectID;
|
||||
|
||||
return query(new QueryStatement<List<GeoInfo>>(sql, 100) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, uuid.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GeoInfo> processResults(ResultSet set) throws SQLException {
|
||||
List<GeoInfo> geoInfo = new ArrayList<>();
|
||||
while (set.next()) {
|
||||
String ip = set.getString(Col.IP.get());
|
||||
String geolocation = set.getString(Col.GEOLOCATION.get());
|
||||
String ipHash = set.getString(Col.IP_HASH.get());
|
||||
long lastUsed = set.getLong(Col.LAST_USED.get());
|
||||
geoInfo.add(new GeoInfo(ip, geolocation, lastUsed, ipHash));
|
||||
try {
|
||||
return query(new QueryStatement<List<GeoInfo>>(sql, 100) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, uuid.toString());
|
||||
}
|
||||
return geoInfo;
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public List<GeoInfo> processResults(ResultSet set) throws SQLException {
|
||||
List<GeoInfo> geoInfo = new ArrayList<>();
|
||||
while (set.next()) {
|
||||
String ip = set.getString(Col.IP.get());
|
||||
String geolocation = set.getString(Col.GEOLOCATION.get());
|
||||
String ipHash = set.getString(Col.IP_HASH.get());
|
||||
long lastUsed = set.getLong(Col.LAST_USED.get());
|
||||
geoInfo.add(new GeoInfo(ip, geolocation, lastUsed, ipHash));
|
||||
}
|
||||
return geoInfo;
|
||||
}
|
||||
});
|
||||
} catch (SQLException e) {
|
||||
throw new DBOpException("SQL Failed: " + sql, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateGeoInfo(UUID uuid, GeoInfo info) throws SQLException {
|
||||
|
@ -27,6 +27,8 @@ import java.util.*;
|
||||
*/
|
||||
public class NicknamesTable extends UserIDTable {
|
||||
|
||||
// TODO Add last used
|
||||
|
||||
public NicknamesTable(SQLDB db) {
|
||||
super("plan_nicknames", db);
|
||||
serverTable = db.getServerTable();
|
||||
|
@ -1,7 +1,11 @@
|
||||
package com.djrapitops.plan.system.database.databases.sql.tables;
|
||||
|
||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.api.exceptions.database.DBOpException;
|
||||
import com.djrapitops.plan.data.container.UserInfo;
|
||||
import com.djrapitops.plan.data.store.Key;
|
||||
import com.djrapitops.plan.data.store.containers.DataContainer;
|
||||
import com.djrapitops.plan.data.store.keys.PlayerKeys;
|
||||
import com.djrapitops.plan.system.database.databases.sql.SQLDB;
|
||||
import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement;
|
||||
import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement;
|
||||
@ -13,6 +17,7 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Table that is in charge of storing common player data for all servers.
|
||||
@ -457,6 +462,47 @@ public class UsersTable extends UserIDTable {
|
||||
});
|
||||
}
|
||||
|
||||
public DataContainer getUserInformation(UUID uuid) {
|
||||
Key<DataContainer> key = new Key<>(DataContainer.class, "plan_users_data");
|
||||
DataContainer returnValue = new DataContainer();
|
||||
|
||||
Supplier<DataContainer> usersTableResults = () -> {
|
||||
try {
|
||||
String sql = "SELECT * FROM " + tableName + " WHERE " + Col.UUID + "=?";
|
||||
|
||||
return query(new QueryStatement<DataContainer>(sql) {
|
||||
@Override
|
||||
public void prepare(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, uuid.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataContainer processResults(ResultSet set) throws SQLException {
|
||||
DataContainer container = new DataContainer();
|
||||
|
||||
if (set.next()) {
|
||||
long registered = set.getLong(Col.REGISTERED.get());
|
||||
String name = set.getString(Col.USER_NAME.get());
|
||||
|
||||
container.putRawData(PlayerKeys.REGISTERED, registered);
|
||||
container.putRawData(PlayerKeys.NAME, name);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
});
|
||||
} catch (SQLException e) {
|
||||
throw new DBOpException("Failed to fetch user info from plan_users", e);
|
||||
}
|
||||
};
|
||||
|
||||
returnValue.putSupplier(key, usersTableResults);
|
||||
returnValue.putRawData(PlayerKeys.UUID, uuid);
|
||||
returnValue.putSupplier(PlayerKeys.REGISTERED, () -> returnValue.getUnsafe(key).getUnsafe(PlayerKeys.REGISTERED));
|
||||
returnValue.putSupplier(PlayerKeys.NAME, () -> returnValue.getUnsafe(key).getUnsafe(PlayerKeys.NAME));
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public enum Col implements Column {
|
||||
ID("id"),
|
||||
UUID("uuid"),
|
||||
|
@ -11,6 +11,8 @@ import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
||||
import com.djrapitops.plan.data.Actions;
|
||||
import com.djrapitops.plan.data.WebUser;
|
||||
import com.djrapitops.plan.data.container.*;
|
||||
import com.djrapitops.plan.data.store.containers.PlayerContainer;
|
||||
import com.djrapitops.plan.data.store.keys.PlayerKeys;
|
||||
import com.djrapitops.plan.data.time.GMTimes;
|
||||
import com.djrapitops.plan.data.time.WorldTimes;
|
||||
import com.djrapitops.plan.system.database.databases.sql.SQLDB;
|
||||
@ -23,16 +25,14 @@ import com.djrapitops.plan.utilities.Base64Util;
|
||||
import com.djrapitops.plan.utilities.SHA256Hash;
|
||||
import com.djrapitops.plan.utilities.analysis.MathUtils;
|
||||
import com.djrapitops.plugin.StaticHolder;
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import com.djrapitops.plugin.api.utility.log.Log;
|
||||
import org.junit.*;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.rules.Timeout;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import utilities.RandomData;
|
||||
import utilities.Teardown;
|
||||
import utilities.TestConstants;
|
||||
import utilities.TestErrorManager;
|
||||
import utilities.*;
|
||||
import utilities.mocks.SystemMockUtil;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
@ -1032,4 +1032,25 @@ public class SQLiteTest {
|
||||
assertNotNull(after.get(2));
|
||||
assertEquals(1, after.get(2).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewContainerForPlayer() throws UnsupportedEncodingException, SQLException, NoSuchAlgorithmException {
|
||||
saveAllData(db);
|
||||
|
||||
long start = System.nanoTime();
|
||||
|
||||
PlayerContainer container = db.fetch().getPlayerContainer(playerUUID);
|
||||
|
||||
assertTrue(container.supports(PlayerKeys.UUID));
|
||||
assertTrue(container.supports(PlayerKeys.REGISTERED));
|
||||
assertTrue(container.supports(PlayerKeys.NAME));
|
||||
|
||||
long end = System.nanoTime();
|
||||
|
||||
assertFalse("Took too long: " + ((end - start) / 1000000.0) + "ms", end - start > TimeAmount.SECOND.ns());
|
||||
|
||||
OptionalAssert.equals(playerUUID, container.getValue(PlayerKeys.UUID));
|
||||
OptionalAssert.equals(123456789L, container.getValue(PlayerKeys.REGISTERED));
|
||||
OptionalAssert.equals("Test", container.getValue(PlayerKeys.NAME));
|
||||
}
|
||||
}
|
||||
|
20
Plan/src/test/java/utilities/OptionalAssert.java
Normal file
20
Plan/src/test/java/utilities/OptionalAssert.java
Normal file
@ -0,0 +1,20 @@
|
||||
package utilities;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Utility for asserts containing Optionals.
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class OptionalAssert {
|
||||
|
||||
public static <T> void equals(T expected, Optional<T> result) {
|
||||
assertTrue(result.isPresent());
|
||||
assertEquals(expected, result.get());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user