Files
SHiNE-server/SHiNE-server/shine-server-db/src/main/java/shine/db/dao/CurrentUsersDAO.java
T

221 lines
8.4 KiB
Java

package shine.db.dao;
import shine.db.DbController;
import shine.db.KeyEncodingUtil;
import shine.db.entities.CurrentUserEntry;
import shine.db.sql.CurrentUsersSql;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* CurrentUsersDAO — совместимый runtime-доступ к текущему срезу пользователей.
*
* Источник:
* - solana_user_pda_current
*
* Колонки:
* - login TEXT PRIMARY KEY
* - blockchain_name TEXT NOT NULL
* - solana_key TEXT NOT NULL
* - blockchain_key TEXT NOT NULL
* - client_key TEXT NOT NULL
*
* Правило работы с соединениями:
* - методы с Connection НЕ закрывают соединение
* - методы без Connection сами открывают и закрывают соединение
*/
public final class CurrentUsersDAO {
private static volatile CurrentUsersDAO instance;
private final DbController db = DbController.getInstance();
private CurrentUsersDAO() {}
public static CurrentUsersDAO getInstance() {
if (instance == null) {
synchronized (CurrentUsersDAO.class) {
if (instance == null) instance = new CurrentUsersDAO();
}
}
return instance;
}
// -------------------- EXISTS --------------------
/** Проверка существования по login (case-insensitive) с внешним соединением. Соединение НЕ закрывает. */
public boolean existsByLogin(Connection c, String login) throws SQLException {
String sql = """
SELECT 1
FROM %s
WHERE normalized_login = LOWER(BTRIM(?))
LIMIT 1
""".formatted(CurrentUsersSql.usersSubquery("su"));
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, login);
try (ResultSet rs = ps.executeQuery()) {
return rs.next();
}
}
}
/** Проверка существования по login (case-insensitive) без внешнего соединения. Сам открывает/закрывает. */
public boolean existsByLogin(String login) throws SQLException {
try (Connection c = db.getConnection()) {
return existsByLogin(c, login);
}
}
/** Проверка существования по blockchain_name (case-sensitive, как в БД) с внешним соединением. */
public boolean existsByBlockchainName(Connection c, String blockchainName) throws SQLException {
String sql = """
SELECT 1
FROM %s
WHERE blockchain_name = ?
LIMIT 1
""".formatted(CurrentUsersSql.usersSubquery("su"));
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, blockchainName);
try (ResultSet rs = ps.executeQuery()) {
return rs.next();
}
}
}
/** Проверка существования по blockchain_name без внешнего соединения. */
public boolean existsByBlockchainName(String blockchainName) throws SQLException {
try (Connection c = db.getConnection()) {
return existsByBlockchainName(c, blockchainName);
}
}
// -------------------- SELECT --------------------
/** Получить по login (case-insensitive) с внешним соединением. Соединение НЕ закрывает. */
public CurrentUserEntry getByLogin(Connection c, String login) throws SQLException {
String sql = """
SELECT
login,
blockchain_name,
solana_key,
blockchain_key,
client_key
FROM %s
WHERE normalized_login = LOWER(BTRIM(?))
""".formatted(CurrentUsersSql.usersSubquery("su"));
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, login);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) return null;
return mapRow(rs);
}
}
}
/** Получить по login (case-insensitive) без внешнего соединения. Сам открывает/закрывает. */
public CurrentUserEntry getByLogin(String login) throws SQLException {
try (Connection c = db.getConnection()) {
return getByLogin(c, login);
}
}
/** Получить по blockchain_name (case-sensitive) с внешним соединением. Соединение НЕ закрывает. */
public CurrentUserEntry getByBlockchainName(Connection c, String blockchainName) throws SQLException {
String sql = """
SELECT
login,
blockchain_name,
solana_key,
blockchain_key,
client_key
FROM %s
WHERE blockchain_name = ?
""".formatted(CurrentUsersSql.usersSubquery("su"));
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, blockchainName);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) return null;
return mapRow(rs);
}
}
}
/** Получить по blockchain_name без внешнего соединения. */
public CurrentUserEntry getByBlockchainName(String blockchainName) throws SQLException {
try (Connection c = db.getConnection()) {
return getByBlockchainName(c, blockchainName);
}
}
/** Поиск по префиксу с внешним соединением. Соединение НЕ закрывает. */
public List<CurrentUserEntry> searchByLoginPrefix(Connection c, String prefix) throws SQLException {
return searchByLoginPrefix(c, prefix, null);
}
/** Поиск по префиксу с optional-фильтром server PDA. Соединение НЕ закрывает. */
public List<CurrentUserEntry> searchByLoginPrefix(Connection c, String prefix, Boolean isServer) throws SQLException {
String sql = """
SELECT
login,
blockchain_name,
solana_key,
blockchain_key,
client_key
FROM %s
WHERE normalized_login LIKE LOWER(BTRIM(?))
AND (? IS NULL OR is_server = ?)
ORDER BY login
LIMIT 5
""".formatted(CurrentUsersSql.usersSubquery("su"));
List<CurrentUserEntry> result = new ArrayList<>();
try (PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, prefix.trim() + "%");
if (isServer == null) {
ps.setNull(2, Types.BOOLEAN);
ps.setNull(3, Types.BOOLEAN);
} else {
ps.setBoolean(2, isServer);
ps.setBoolean(3, isServer);
}
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) result.add(mapRow(rs));
}
}
return result;
}
/** Поиск по префиксу без внешнего соединения. Сам открывает/закрывает. */
public List<CurrentUserEntry> searchByLoginPrefix(String prefix) throws SQLException {
return searchByLoginPrefix(prefix, null);
}
/** Поиск по префиксу без внешнего соединения с optional-фильтром server PDA. */
public List<CurrentUserEntry> searchByLoginPrefix(String prefix, Boolean isServer) throws SQLException {
try (Connection c = db.getConnection()) {
return searchByLoginPrefix(c, prefix, isServer);
}
}
// -------------------- MAPPER --------------------
private CurrentUserEntry mapRow(ResultSet rs) throws SQLException {
CurrentUserEntry e = new CurrentUserEntry();
e.setLogin(rs.getString("login"));
e.setBlockchainName(rs.getString("blockchain_name"));
e.setSolanaKey(KeyEncodingUtil.normalizeKeyToBase64_32(rs.getString("solana_key")));
e.setBlockchainKey(KeyEncodingUtil.normalizeKeyToBase64_32(rs.getString("blockchain_key")));
e.setClientKey(KeyEncodingUtil.normalizeKeyToBase64_32(rs.getString("client_key")));
return e;
}
}