Don't create backing tables on startup

This commit is contained in:
cnr 2016-05-25 10:25:49 -05:00
parent 5331e2bec9
commit 1c66c10293

View File

@ -1,5 +1,6 @@
package mineplex.core.database; package mineplex.core.database;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import mineplex.serverdata.database.DBPool; import mineplex.serverdata.database.DBPool;
@ -20,22 +21,31 @@ import java.util.concurrent.CompletableFuture;
* <p> * <p>
* {@code new PlayerKeyValueRepository("tableName", PreparedStatement::setString, ResultSet::getString, "VARCHAR(255)")} * {@code new PlayerKeyValueRepository("tableName", PreparedStatement::setString, ResultSet::getString, "VARCHAR(255)")}
* <p> * <p>
* NOTE: EACH CONSTRUCTOR IS BLOCKING, and initializes a backing table * Compatible backing table schemas can be written as follows (replace $VARS as appropriate):
* if one does not yet exist * <p><blockquote><pre>
* 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)
* )}
* </pre></blockquote></p>
* *
* @param <V> The value type to use for this repository * @param <V> The value type to use for this repository
*/ */
public class PlayerKeyValueRepository<V> public class PlayerKeyValueRepository<V>
{ {
private static final ImmutableMap<Class<?>, ValueMapper<?>> PRIM_MAPPERS = ImmutableMap.<Class<?>, ValueMapper<?>>builder() private static final ImmutableMap<Class<?>, ValueMapper<?>> PRIM_MAPPERS = ImmutableMap.<Class<?>, ValueMapper<?>>builder()
.put(String.class, new ValueMapper<>(PreparedStatement::setString, ResultSet::getString, "VARCHAR(255)")) .put(String.class, new ValueMapper<>(PreparedStatement::setString, ResultSet::getString))
.put(Boolean.class, new ValueMapper<>(PreparedStatement::setBoolean, ResultSet::getBoolean, "BOOL")) .put(Boolean.class, new ValueMapper<>(PreparedStatement::setBoolean, ResultSet::getBoolean))
.put(Byte.class, new ValueMapper<>(PreparedStatement::setByte, ResultSet::getByte, "TINYINT")) .put(Byte.class, new ValueMapper<>(PreparedStatement::setByte, ResultSet::getByte))
.put(Short.class, new ValueMapper<>(PreparedStatement::setShort, ResultSet::getShort, "SMALLINT")) .put(Short.class, new ValueMapper<>(PreparedStatement::setShort, ResultSet::getShort))
.put(Integer.class, new ValueMapper<>(PreparedStatement::setInt, ResultSet::getInt, "INTEGER")) .put(Integer.class, new ValueMapper<>(PreparedStatement::setInt, ResultSet::getInt))
.put(Long.class, new ValueMapper<>(PreparedStatement::setLong, ResultSet::getLong, "BIGINT")) .put(Long.class, new ValueMapper<>(PreparedStatement::setLong, ResultSet::getLong))
.put(Float.class, new ValueMapper<>(PreparedStatement::setFloat, ResultSet::getFloat, "REAL")) .put(Float.class, new ValueMapper<>(PreparedStatement::setFloat, ResultSet::getFloat))
.put(Double.class, new ValueMapper<>(PreparedStatement::setDouble, ResultSet::getDouble, "DOUBLE")) .put(Double.class, new ValueMapper<>(PreparedStatement::setDouble, ResultSet::getDouble))
.build(); .build();
private final String _tableName; private final String _tableName;
private final ValueMapper<V> _mapper; private final ValueMapper<V> _mapper;
@ -51,7 +61,11 @@ public class PlayerKeyValueRepository<V>
@SuppressWarnings("unchecked") // java's generics are garbage. @SuppressWarnings("unchecked") // java's generics are garbage.
public PlayerKeyValueRepository(String tableName, Class<V> clazz) // we could infer the type parameter at runtime, but it's super ugly public PlayerKeyValueRepository(String tableName, Class<V> clazz) // we could infer the type parameter at runtime, but it's super ugly
{ {
this(tableName, (ValueMapper<V>) PRIM_MAPPERS.get(clazz)); ValueMapper<V> mapper = (ValueMapper<V>) 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<V>
* @param serializer the serializing function used to insert values * @param serializer the serializing function used to insert values
* @param deserializer the deserializing function used to retrieve * @param deserializer the deserializing function used to retrieve
* values * values
* @param columnDef the value type's SQL datatype declaration, e.g., {@code "VARCHAR(255)"} for Strings.
*/ */
public PlayerKeyValueRepository(String tableName, Serializer<V> serializer, Deserializer<V> deserializer, String columnDef) public PlayerKeyValueRepository(String tableName, Serializer<V> serializer, Deserializer<V> deserializer)
{
this(tableName, new ValueMapper<V>(serializer, deserializer, columnDef));
}
private PlayerKeyValueRepository(String tableName, ValueMapper<V> mapper)
{ {
this._tableName = tableName; this._tableName = tableName;
this._mapper = mapper; this._mapper = new ValueMapper<V>(serializer, deserializer);
// 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();
}
} }
/** /**
@ -279,13 +269,11 @@ public class PlayerKeyValueRepository<V>
{ {
private final Serializer<V> _serializer; private final Serializer<V> _serializer;
private final Deserializer<V> _deserializer; private final Deserializer<V> _deserializer;
private final String _columnDef;
private ValueMapper(Serializer<V> serializer, Deserializer<V> deserializer, String columnDef) private ValueMapper(Serializer<V> serializer, Deserializer<V> deserializer)
{ {
_serializer = serializer; _serializer = serializer;
_deserializer = deserializer; _deserializer = deserializer;
_columnDef = columnDef;
} }
} }