Reworked database setup and added pagination
The database tables are now automatically created The history lookup now uses a view for names (for simplicity and readability) The all history lookup now uses a view combining all punishment history for efficiency
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
package com.alttd.altitudeweb.setup;
|
||||
|
||||
import com.alttd.altitudeweb.database.Databases;
|
||||
import com.alttd.altitudeweb.database.web_db.DatabaseSettings;
|
||||
import com.alttd.altitudeweb.database.web_db.SettingsMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.datasource.pooled.PooledDataSource;
|
||||
import org.apache.ibatis.mapping.Environment;
|
||||
import org.apache.ibatis.session.Configuration;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
|
||||
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Slf4j
|
||||
public class Connection {
|
||||
|
||||
private static final HashMap<Databases, Connection> connections = new HashMap<>();
|
||||
private SqlSessionFactory sqlSessionFactory;
|
||||
private final DatabaseSettings settings;
|
||||
private final AddMappers addMappers;
|
||||
|
||||
private Connection(DatabaseSettings settings, AddMappers addMappers) {
|
||||
this.settings = settings;
|
||||
this.addMappers = addMappers;
|
||||
}
|
||||
|
||||
public static void initDatabases() {
|
||||
InitializeWebDb.init();
|
||||
InitializeLiteBans.init();
|
||||
InitializeLuckPerms.init();
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface AddMappers {
|
||||
void apply(Configuration configuration);
|
||||
}
|
||||
|
||||
public static Connection getConnection(Databases database) {
|
||||
if (connections.containsKey(database)) {
|
||||
return connections.get(database);
|
||||
}
|
||||
throw new RuntimeException("Database " + database + " has not been initialized");
|
||||
}
|
||||
|
||||
protected static CompletableFuture<Connection> getConnection(Databases database, AddMappers addMappers) {
|
||||
if (connections.containsKey(database)) {
|
||||
return CompletableFuture.completedFuture(connections.get(database));
|
||||
}
|
||||
if (database == Databases.DEFAULT) {
|
||||
return loadDefaultDatabase(addMappers);
|
||||
}
|
||||
CompletableFuture<DatabaseSettings> settingsFuture = new CompletableFuture<>();
|
||||
getConnection(Databases.DEFAULT, (mapper -> mapper.addMapper(SettingsMapper.class))).thenApply(connection -> {
|
||||
log.debug("Loading settings for database {}", database.getInternalName());
|
||||
connection.runQuery(session -> {
|
||||
log.debug("Running query to load settings for database");
|
||||
DatabaseSettings loadedSettings = session.getMapper(SettingsMapper.class).getSettings(database.getInternalName());
|
||||
if (loadedSettings == null) {
|
||||
log.error("Failed to load settings for database {}", database.getInternalName());
|
||||
}
|
||||
log.debug("Loaded settings {}", loadedSettings);
|
||||
settingsFuture.complete(loadedSettings);
|
||||
});
|
||||
return null;
|
||||
});
|
||||
return settingsFuture.thenApply(loadedSettings -> {
|
||||
log.debug("Storing connection for database {}", database.getInternalName());
|
||||
Connection connection = new Connection(loadedSettings, addMappers);
|
||||
connections.put(database, connection);
|
||||
return connection;
|
||||
});
|
||||
}
|
||||
|
||||
private static CompletableFuture<Connection> loadDefaultDatabase(AddMappers addMappers) {
|
||||
DatabaseSettings databaseSettings = new DatabaseSettings(
|
||||
System.getenv("DB_HOST"),
|
||||
Integer.parseInt(System.getenv("DB_PORT")),
|
||||
System.getenv("DB_NAME"),
|
||||
System.getenv("DB_USER"),
|
||||
System.getenv("DB_PASS")
|
||||
);
|
||||
log.debug("Loaded default database settings {}", databaseSettings);
|
||||
Connection connection = new Connection(databaseSettings, addMappers);
|
||||
log.debug("Created default database connection {}", connection);
|
||||
return CompletableFuture.completedFuture(connection);
|
||||
}
|
||||
|
||||
public void runQuery(Consumer<SqlSession> consumer) {
|
||||
new Thread(() -> {
|
||||
if (sqlSessionFactory == null) {
|
||||
sqlSessionFactory = createSqlSessionFactory(settings, addMappers);
|
||||
}
|
||||
|
||||
try (SqlSession session = sqlSessionFactory.openSession()) {
|
||||
consumer.accept(session);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to run query", e);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private SqlSessionFactory createSqlSessionFactory(DatabaseSettings settings, AddMappers addMappers) {
|
||||
PooledDataSource dataSource = new PooledDataSource();
|
||||
dataSource.setDriver("com.mysql.cj.jdbc.Driver");
|
||||
dataSource.setUrl(String.format("jdbc:mysql://%s:%d/%s", settings.host(),
|
||||
settings.port(), settings.name()));
|
||||
dataSource.setUsername(settings.username());
|
||||
dataSource.setPassword(settings.password());
|
||||
Environment environment = new Environment("production", new JdbcTransactionFactory(), dataSource);
|
||||
Configuration configuration = new Configuration(environment);
|
||||
addMappers.apply(configuration);
|
||||
|
||||
return new SqlSessionFactoryBuilder().build(configuration);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.alttd.altitudeweb.setup;
|
||||
|
||||
import com.alttd.altitudeweb.database.Databases;
|
||||
import com.alttd.altitudeweb.database.litebans.NameHistoryMapper;
|
||||
import com.alttd.altitudeweb.database.litebans.RecentNamesMapper;
|
||||
import com.alttd.altitudeweb.database.litebans.UUIDHistoryMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
@Slf4j
|
||||
public class InitializeLiteBans {
|
||||
|
||||
protected static void init() {
|
||||
log.info("Initializing LiteBans");
|
||||
Connection.getConnection(Databases.LITE_BANS, (configuration) -> {
|
||||
configuration.addMapper(RecentNamesMapper.class);
|
||||
configuration.addMapper(NameHistoryMapper.class);
|
||||
configuration.addMapper(UUIDHistoryMapper.class);
|
||||
}).join()
|
||||
.runQuery(sqlSession -> {
|
||||
createAllPunishmentsView(sqlSession);
|
||||
createUserLookupView(sqlSession);
|
||||
});
|
||||
log.debug("Initialized LiteBans");
|
||||
}
|
||||
|
||||
private static void createAllPunishmentsView(SqlSession sqlSession) {
|
||||
String query = """
|
||||
CREATE VIEW IF NOT EXISTS all_punishments AS
|
||||
SELECT uuid, reason, banned_by_uuid, banned_by_name, removed_by_name, time, until, removed_by_reason,
|
||||
'ban' as type
|
||||
FROM litebans_bans
|
||||
UNION ALL
|
||||
SELECT uuid, reason, banned_by_uuid, banned_by_name, removed_by_name, time, until, removed_by_reason,
|
||||
'mute' as type
|
||||
FROM litebans_mutes
|
||||
UNION ALL
|
||||
SELECT uuid, reason, banned_by_uuid, banned_by_name, removed_by_name, time, until, removed_by_reason,
|
||||
'warn' as type
|
||||
FROM litebans_warnings
|
||||
ORDER BY time DESC;
|
||||
""";
|
||||
try (Statement statement = sqlSession.getConnection().createStatement()) {
|
||||
statement.execute(query);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void createUserLookupView(SqlSession sqlSession) {
|
||||
String query = """
|
||||
CREATE VIEW IF NOT EXISTS user_lookup AS
|
||||
SELECT history_1.uuid, history_1.name
|
||||
FROM litebans.litebans_history history_1
|
||||
INNER JOIN (
|
||||
SELECT uuid, MAX(id) as max_id
|
||||
FROM litebans.litebans_history
|
||||
GROUP BY uuid
|
||||
) history_2 ON history_1.uuid = history_2.uuid AND history_1.id = history_2.max_id
|
||||
""";
|
||||
try (Statement statement = sqlSession.getConnection().createStatement()) {
|
||||
statement.execute(query);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.alttd.altitudeweb.setup;
|
||||
|
||||
import com.alttd.altitudeweb.database.Databases;
|
||||
import com.alttd.altitudeweb.database.luckperms.TeamMemberMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class InitializeLuckPerms {
|
||||
|
||||
protected static void init() {
|
||||
log.info("Initializing LuckPerms");
|
||||
Connection.getConnection(Databases.LUCK_PERMS, (configuration) -> {
|
||||
configuration.addMapper(TeamMemberMapper.class);
|
||||
}).join();
|
||||
log.debug("Initialized LuckPerms");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.alttd.altitudeweb.setup;
|
||||
|
||||
import com.alttd.altitudeweb.database.Databases;
|
||||
import com.alttd.altitudeweb.database.web_db.SettingsMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
@Slf4j
|
||||
public class InitializeWebDb {
|
||||
|
||||
protected static void init() {
|
||||
log.info("Initializing LiteBans");
|
||||
Connection.getConnection(Databases.DEFAULT, (configuration) -> {
|
||||
configuration.addMapper(SettingsMapper.class);
|
||||
}).join()
|
||||
.runQuery(InitializeWebDb::createSettingsTable);
|
||||
log.debug("Initialized LuckPerms");
|
||||
}
|
||||
|
||||
private static void createSettingsTable(SqlSession sqlSession) {
|
||||
String query = """
|
||||
CREATE TABLE IF NOT EXISTS db_connection_settings
|
||||
(
|
||||
internal_name VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
username VARCHAR(255) NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
host VARCHAR(255) NOT NULL,
|
||||
port INT NOT NULL,
|
||||
CONSTRAINT pk_internal_name PRIMARY KEY (internal_name)
|
||||
);
|
||||
""";
|
||||
try (Statement statement = sqlSession.getConnection().createStatement()) {
|
||||
statement.execute(query);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user