mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-01-14 20:21:45 +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;
|
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.FormatUtils;
|
||||||
import com.djrapitops.plan.utilities.SHA256Hash;
|
import com.djrapitops.plan.utilities.SHA256Hash;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
@ -35,6 +36,14 @@ public class GeoInfo {
|
|||||||
this.ipHash = ipHash;
|
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() {
|
public String getIp() {
|
||||||
return ip;
|
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.ServerProfile;
|
||||||
import com.djrapitops.plan.data.WebUser;
|
import com.djrapitops.plan.data.WebUser;
|
||||||
import com.djrapitops.plan.data.container.*;
|
import com.djrapitops.plan.data.container.*;
|
||||||
|
import com.djrapitops.plan.data.store.containers.PlayerContainer;
|
||||||
import com.djrapitops.plan.system.info.server.Server;
|
import com.djrapitops.plan.system.info.server.Server;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -21,6 +22,8 @@ public interface FetchOperations {
|
|||||||
|
|
||||||
// UUIDs
|
// UUIDs
|
||||||
|
|
||||||
|
PlayerContainer getPlayerContainer(UUID uuid);
|
||||||
|
|
||||||
Set<UUID> getSavedUUIDs() throws DBException;
|
Set<UUID> getSavedUUIDs() throws DBException;
|
||||||
|
|
||||||
Set<UUID> getSavedUUIDs(UUID server) throws DBException;
|
Set<UUID> getSavedUUIDs(UUID server) throws DBException;
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package com.djrapitops.plan.system.database.databases.sql.operation;
|
package com.djrapitops.plan.system.database.databases.sql.operation;
|
||||||
|
|
||||||
import com.djrapitops.plan.api.exceptions.database.DBException;
|
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.PlayerProfile;
|
||||||
import com.djrapitops.plan.data.ServerProfile;
|
import com.djrapitops.plan.data.ServerProfile;
|
||||||
import com.djrapitops.plan.data.WebUser;
|
import com.djrapitops.plan.data.WebUser;
|
||||||
import com.djrapitops.plan.data.container.*;
|
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.operation.FetchOperations;
|
||||||
import com.djrapitops.plan.system.database.databases.sql.SQLDB;
|
import com.djrapitops.plan.system.database.databases.sql.SQLDB;
|
||||||
import com.djrapitops.plan.system.info.server.Server;
|
import com.djrapitops.plan.system.info.server.Server;
|
||||||
@ -116,9 +119,22 @@ public class SQLFetchOps extends SQLOps implements FetchOperations {
|
|||||||
return profile;
|
return profile;
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw SQLErrorUtil.getExceptionFor(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) {
|
private void addUserInfoToProfile(PlayerProfile profile, Map<UUID, UserInfo> userInfo) {
|
||||||
for (Map.Entry<UUID, UserInfo> entry : userInfo.entrySet()) {
|
for (Map.Entry<UUID, UserInfo> entry : userInfo.entrySet()) {
|
||||||
UUID serverUUID = entry.getKey();
|
UUID serverUUID = entry.getKey();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.djrapitops.plan.system.database.databases.sql.tables;
|
package com.djrapitops.plan.system.database.databases.sql.tables;
|
||||||
|
|
||||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
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.data.container.GeoInfo;
|
||||||
import com.djrapitops.plan.system.database.databases.sql.SQLDB;
|
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.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 +
|
String sql = "SELECT DISTINCT * FROM " + tableName +
|
||||||
" WHERE " + Col.USER_ID + "=" + usersTable.statementSelectID;
|
" WHERE " + Col.USER_ID + "=" + usersTable.statementSelectID;
|
||||||
|
|
||||||
return query(new QueryStatement<List<GeoInfo>>(sql, 100) {
|
try {
|
||||||
@Override
|
return query(new QueryStatement<List<GeoInfo>>(sql, 100) {
|
||||||
public void prepare(PreparedStatement statement) throws SQLException {
|
@Override
|
||||||
statement.setString(1, uuid.toString());
|
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));
|
|
||||||
}
|
}
|
||||||
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 {
|
private void updateGeoInfo(UUID uuid, GeoInfo info) throws SQLException {
|
||||||
|
@ -27,6 +27,8 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class NicknamesTable extends UserIDTable {
|
public class NicknamesTable extends UserIDTable {
|
||||||
|
|
||||||
|
// TODO Add last used
|
||||||
|
|
||||||
public NicknamesTable(SQLDB db) {
|
public NicknamesTable(SQLDB db) {
|
||||||
super("plan_nicknames", db);
|
super("plan_nicknames", db);
|
||||||
serverTable = db.getServerTable();
|
serverTable = db.getServerTable();
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package com.djrapitops.plan.system.database.databases.sql.tables;
|
package com.djrapitops.plan.system.database.databases.sql.tables;
|
||||||
|
|
||||||
import com.djrapitops.plan.api.exceptions.database.DBInitException;
|
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.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.SQLDB;
|
||||||
import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement;
|
import com.djrapitops.plan.system.database.databases.sql.processing.ExecStatement;
|
||||||
import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement;
|
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.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table that is in charge of storing common player data for all servers.
|
* 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 {
|
public enum Col implements Column {
|
||||||
ID("id"),
|
ID("id"),
|
||||||
UUID("uuid"),
|
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.Actions;
|
||||||
import com.djrapitops.plan.data.WebUser;
|
import com.djrapitops.plan.data.WebUser;
|
||||||
import com.djrapitops.plan.data.container.*;
|
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.GMTimes;
|
||||||
import com.djrapitops.plan.data.time.WorldTimes;
|
import com.djrapitops.plan.data.time.WorldTimes;
|
||||||
import com.djrapitops.plan.system.database.databases.sql.SQLDB;
|
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.SHA256Hash;
|
||||||
import com.djrapitops.plan.utilities.analysis.MathUtils;
|
import com.djrapitops.plan.utilities.analysis.MathUtils;
|
||||||
import com.djrapitops.plugin.StaticHolder;
|
import com.djrapitops.plugin.StaticHolder;
|
||||||
|
import com.djrapitops.plugin.api.TimeAmount;
|
||||||
import com.djrapitops.plugin.api.utility.log.Log;
|
import com.djrapitops.plugin.api.utility.log.Log;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import org.junit.rules.TemporaryFolder;
|
import org.junit.rules.TemporaryFolder;
|
||||||
import org.junit.rules.Timeout;
|
import org.junit.rules.Timeout;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import utilities.RandomData;
|
import utilities.*;
|
||||||
import utilities.Teardown;
|
|
||||||
import utilities.TestConstants;
|
|
||||||
import utilities.TestErrorManager;
|
|
||||||
import utilities.mocks.SystemMockUtil;
|
import utilities.mocks.SystemMockUtil;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
@ -1032,4 +1032,25 @@ public class SQLiteTest {
|
|||||||
assertNotNull(after.get(2));
|
assertNotNull(after.get(2));
|
||||||
assertEquals(1, after.get(2).size());
|
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