diff --git a/Plugins/Mineplex.Core/src/mineplex/core/database/PlayerKeyValueRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/database/PlayerKeyValueRepository.java
index 74efc5086..9325679ae 100644
--- a/Plugins/Mineplex.Core/src/mineplex/core/database/PlayerKeyValueRepository.java
+++ b/Plugins/Mineplex.Core/src/mineplex/core/database/PlayerKeyValueRepository.java
@@ -1,5 +1,6 @@
package mineplex.core.database;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import mineplex.serverdata.database.DBPool;
@@ -20,22 +21,31 @@ import java.util.concurrent.CompletableFuture;
*
* {@code new PlayerKeyValueRepository("tableName", PreparedStatement::setString, ResultSet::getString, "VARCHAR(255)")}
*
- * NOTE: EACH CONSTRUCTOR IS BLOCKING, and initializes a backing table
- * if one does not yet exist
+ * Compatible backing table schemas can be written as follows (replace $VARS as appropriate):
+ *
+ * CREATE TABLE IF NOT EXISTS $TABLE_NAME (
+ * accountId INT NOT NULL,
+ * kvKey VARCHAR(255) NOT NULL,
+ * kvValue $VALUE_COLUMN_TYPE
+ * PRIMARY KEY (accountId,kvKey),
+ * INDEX acc_ind (accountId),
+ * FOREIGN KEY (accountId) REFERENCES accounts(id)
+ * )}
+ *
*
* @param The value type to use for this repository
*/
public class PlayerKeyValueRepository
{
private static final ImmutableMap, ValueMapper>> PRIM_MAPPERS = ImmutableMap., ValueMapper>>builder()
- .put(String.class, new ValueMapper<>(PreparedStatement::setString, ResultSet::getString, "VARCHAR(255)"))
- .put(Boolean.class, new ValueMapper<>(PreparedStatement::setBoolean, ResultSet::getBoolean, "BOOL"))
- .put(Byte.class, new ValueMapper<>(PreparedStatement::setByte, ResultSet::getByte, "TINYINT"))
- .put(Short.class, new ValueMapper<>(PreparedStatement::setShort, ResultSet::getShort, "SMALLINT"))
- .put(Integer.class, new ValueMapper<>(PreparedStatement::setInt, ResultSet::getInt, "INTEGER"))
- .put(Long.class, new ValueMapper<>(PreparedStatement::setLong, ResultSet::getLong, "BIGINT"))
- .put(Float.class, new ValueMapper<>(PreparedStatement::setFloat, ResultSet::getFloat, "REAL"))
- .put(Double.class, new ValueMapper<>(PreparedStatement::setDouble, ResultSet::getDouble, "DOUBLE"))
+ .put(String.class, new ValueMapper<>(PreparedStatement::setString, ResultSet::getString))
+ .put(Boolean.class, new ValueMapper<>(PreparedStatement::setBoolean, ResultSet::getBoolean))
+ .put(Byte.class, new ValueMapper<>(PreparedStatement::setByte, ResultSet::getByte))
+ .put(Short.class, new ValueMapper<>(PreparedStatement::setShort, ResultSet::getShort))
+ .put(Integer.class, new ValueMapper<>(PreparedStatement::setInt, ResultSet::getInt))
+ .put(Long.class, new ValueMapper<>(PreparedStatement::setLong, ResultSet::getLong))
+ .put(Float.class, new ValueMapper<>(PreparedStatement::setFloat, ResultSet::getFloat))
+ .put(Double.class, new ValueMapper<>(PreparedStatement::setDouble, ResultSet::getDouble))
.build();
private final String _tableName;
private final ValueMapper _mapper;
@@ -51,7 +61,11 @@ public class PlayerKeyValueRepository
@SuppressWarnings("unchecked") // java's generics are garbage.
public PlayerKeyValueRepository(String tableName, Class clazz) // we could infer the type parameter at runtime, but it's super ugly
{
- this(tableName, (ValueMapper) PRIM_MAPPERS.get(clazz));
+ ValueMapper mapper = (ValueMapper) PRIM_MAPPERS.get(clazz);
+ Preconditions.checkNotNull(mapper, "Unsupported value type: " + clazz.getName() + ". (use the other constructor)");
+
+ this._tableName = tableName;
+ this._mapper = mapper;
}
/**
@@ -63,35 +77,11 @@ public class PlayerKeyValueRepository
* @param serializer the serializing function used to insert values
* @param deserializer the deserializing function used to retrieve
* values
- * @param columnDef the value type's SQL datatype declaration, e.g., {@code "VARCHAR(255)"} for Strings.
*/
- public PlayerKeyValueRepository(String tableName, Serializer serializer, Deserializer deserializer, String columnDef)
- {
- this(tableName, new ValueMapper(serializer, deserializer, columnDef));
- }
-
- private PlayerKeyValueRepository(String tableName, ValueMapper mapper)
+ public PlayerKeyValueRepository(String tableName, Serializer serializer, Deserializer deserializer)
{
this._tableName = tableName;
- this._mapper = mapper;
-
- // Create a table to back this repository
- try (Connection conn = DBPool.getAccount().getConnection())
- {
- Statement stmt = conn.createStatement();
- stmt.executeUpdate("CREATE TABLE IF NOT EXISTS " + _tableName + "("
- + "accountId INT NOT NULL,"
- + "kvKey VARCHAR(255) NOT NULL,"
- + "kvValue " + _mapper._columnDef + ","
- + "PRIMARY KEY (accountId,kvKey),"
- + "INDEX acc_ind (accountId),"
- + "FOREIGN KEY (accountId) REFERENCES accounts(id) ON DELETE NO ACTION ON UPDATE NO ACTION"
- + ")");
- }
- catch (SQLException e)
- {
- e.printStackTrace();
- }
+ this._mapper = new ValueMapper(serializer, deserializer);
}
/**
@@ -279,13 +269,11 @@ public class PlayerKeyValueRepository
{
private final Serializer _serializer;
private final Deserializer _deserializer;
- private final String _columnDef;
- private ValueMapper(Serializer serializer, Deserializer deserializer, String columnDef)
+ private ValueMapper(Serializer serializer, Deserializer deserializer)
{
_serializer = serializer;
_deserializer = deserializer;
- _columnDef = columnDef;
}
}