fix: we no longer use sql-client-templates

This commit is contained in:
2026-05-08 13:55:46 +03:00
parent fa0b2518af
commit 1531215b43
9 changed files with 175 additions and 208 deletions

View File

@@ -40,7 +40,6 @@ dependencies {
implementation("io.vertx:vertx-launcher-application")
implementation("io.vertx:vertx-web-client")
implementation("io.vertx:vertx-config")
implementation("io.vertx:vertx-sql-client-templates")
implementation("io.vertx:vertx-health-check")
implementation("io.vertx:vertx-web")
implementation("io.vertx:vertx-mysql-client")

View File

@@ -569,7 +569,7 @@ public class MainVerticle extends AbstractVerticle {
return;
}
if (!olapQueryService.isValidTableName(tableName)) {
if (olapQueryService.isValidTableName(tableName)) {
rc.response().setStatusCode(400).end("Invalid tableName: must start with a letter and contain only letters and digits");
return;
}
@@ -606,7 +606,7 @@ public class MainVerticle extends AbstractVerticle {
return;
}
if (!olapQueryService.isValidTableName(tableName)) {
if (olapQueryService.isValidTableName(tableName)) {
rc.response().setStatusCode(400).end("Invalid tableName: must start with a letter and contain only letters and digits");
return;
}

View File

@@ -6,15 +6,14 @@ import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.Tuple;
import io.vertx.sqlclient.templates.SqlTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import su.xserver.iikocon.service.ExternalDataBaseService;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.*;
public class OlapQueryService {
private static final Logger log = LoggerFactory.getLogger(OlapQueryService.class);
private final Pool pool;
private final ExternalDataBaseService externalDataBaseService;
private final SqlGenerator sqlGenerator;
@@ -62,17 +61,16 @@ public class OlapQueryService {
public Future<Integer> createQuery(String name, int dbConnectionId, JsonObject config,
List<Integer> restaurantIds, String generatedSql, boolean active) {
JsonObject fullConfig = generateFullIikoJson(config);
Map<String, Object> params = Map.of(
"name", name,
"db_connection_id", dbConnectionId,
"config_json", config.encode(),
"full_config_json", fullConfig.encode(),
"sql_text", generatedSql != null ? generatedSql : "",
"active", active
String sql = "INSERT INTO olap_queries (name, db_connection_id, config_json, full_config_json, sql_text, active) VALUES (?, ?, ?, ?, ?, ?)";
Tuple params = Tuple.of(
name,
dbConnectionId,
config.encode(),
fullConfig.encode(),
generatedSql != null ? generatedSql : "",
active
);
String sql = "INSERT INTO olap_queries (name, db_connection_id, config_json, full_config_json, sql_text, active) VALUES (#{name}, #{db_connection_id}, #{config_json}, #{full_config_json}, #{sql_text}, #{active})";
return SqlTemplate.forUpdate(pool, sql)
.execute(params)
return pool.preparedQuery(sql).execute(params)
.compose(rows -> getLastInsertId())
.compose(queryId -> linkRestaurants(queryId, restaurantIds).map(queryId));
}
@@ -80,22 +78,23 @@ public class OlapQueryService {
public Future<Void> updateQuery(int id, String name, int dbConnectionId, JsonObject config,
List<Integer> restaurantIds, String generatedSql, boolean active) {
JsonObject fullConfig = generateFullIikoJson(config);
Map<String, Object> params = Map.of(
"id", id,
"name", name,
"db_connection_id", dbConnectionId,
"config_json", config.encode(),
"full_config_json", fullConfig.encode(),
"sql_text", generatedSql != null ? generatedSql : "",
"active", active
String sql = "UPDATE olap_queries SET name = ?, db_connection_id = ?, config_json = ?, full_config_json = ?, sql_text = ?, active = ? WHERE id = ?";
Tuple params = Tuple.of(
name,
dbConnectionId,
config.encode(),
fullConfig.encode(),
generatedSql != null ? generatedSql : "",
active,
id
);
String sql = "UPDATE olap_queries SET name = #{name}, db_connection_id = #{db_connection_id}, config_json = #{config_json}, full_config_json = #{full_config_json}, sql_text = #{sql_text}, active = #{active} WHERE id = #{id}";
return SqlTemplate.forUpdate(pool, sql)
.execute(params)
return pool.preparedQuery(sql).execute(params)
.compose(v -> pool.query("DELETE FROM olap_query_restaurants WHERE query_id = " + id).execute()
.compose(del -> linkRestaurants(id, restaurantIds))).mapEmpty();
.compose(del -> linkRestaurants(id, restaurantIds)))
.mapEmpty();
}
public JsonObject generateFullIikoJson(JsonObject clientConfig) {
String reportType = clientConfig.getString("reportType", "SALES");
boolean buildSummary = clientConfig.getBoolean("buildSummary", false);
@@ -153,17 +152,15 @@ public class OlapQueryService {
}
private JsonObject buildDateFilter(String reportType, String dateToStr, int daysBack) {
// Определяем корректную дату "до" (конец дня)
java.time.ZonedDateTime toDate;
ZonedDateTime toDate;
if (dateToStr != null && !dateToStr.isEmpty()) {
toDate = java.time.LocalDate.parse(dateToStr).atStartOfDay(java.time.ZoneOffset.UTC);
toDate = LocalDate.parse(dateToStr).atStartOfDay(ZoneOffset.UTC);
} else {
toDate = java.time.ZonedDateTime.now(java.time.ZoneOffset.UTC);
toDate = ZonedDateTime.now(ZoneOffset.UTC);
}
toDate = toDate.withHour(23).withMinute(59).withSecond(59).withNano(999_999_999);
java.time.ZonedDateTime fromDate = toDate.minusDays(Math.max(1, daysBack))
ZonedDateTime fromDate = toDate.minusDays(Math.max(1, daysBack))
.withHour(0).withMinute(0).withSecond(0).withNano(0);
String filterKey = "TRANSACTIONS".equals(reportType) ? "DateTime.DateTyped" : "OpenDate.Typed";
return new JsonObject().put(filterKey, new JsonObject()
.put("filterType", "DateRange")
@@ -179,23 +176,19 @@ public class OlapQueryService {
private Future<Void> linkRestaurants(int queryId, List<Integer> restaurantIds) {
if (restaurantIds == null || restaurantIds.isEmpty()) return Future.succeededFuture();
String sql = "INSERT INTO olap_query_restaurants (query_id, restaurant_id) VALUES (?, ?)";
List<Future<Void>> futures = new ArrayList<>();
for (Integer restId : restaurantIds) {
Map<String, Object> params = Map.of("query_id", queryId, "restaurant_id", restId);
futures.add(SqlTemplate.forUpdate(pool,
"INSERT INTO olap_query_restaurants (query_id, restaurant_id) VALUES (#{query_id}, #{restaurant_id})")
.execute(params).mapEmpty());
futures.add(pool.preparedQuery(sql).execute(Tuple.of(queryId, restId)).mapEmpty());
}
return Future.all(futures).mapEmpty();
}
// Удаление
public Future<Void> deleteQuery(int id) {
return SqlTemplate.forUpdate(pool, "DELETE FROM olap_queries WHERE id = #{id}")
.execute(Map.of("id", id)).mapEmpty();
String sql = "DELETE FROM olap_queries WHERE id = ?";
return pool.preparedQuery(sql).execute(Tuple.of(id)).mapEmpty();
}
// Получить все запросы (без config_json, для списка)
public Future<JsonArray> getAllQueries() {
String sql = """
SELECT q.id, q.name, q.db_connection_id, q.active, q.last_run, q.last_run_success, q.created, q.updated,
@@ -226,13 +219,10 @@ public class OlapQueryService {
});
}
// Получить один запрос с полной конфигурацией
public Future<JsonObject> getQueryById(int id) {
String querySql = "SELECT id, name, db_connection_id, config_json, sql_text, active, created, updated FROM olap_queries WHERE id = ?";
String restaurantsSql = "SELECT restaurant_id FROM olap_query_restaurants WHERE query_id = ?";
return pool.preparedQuery(querySql).execute(io.vertx.sqlclient.Tuple.of(id))
return pool.preparedQuery(querySql).execute(Tuple.of(id))
.compose(rows -> {
if (rows.size() == 0) return Future.succeededFuture(null);
Row row = rows.iterator().next();
@@ -245,8 +235,7 @@ public class OlapQueryService {
.put("active", row.getBoolean("active"))
.put("created", row.getLocalDateTime("created") != null ? row.getLocalDateTime("created").toString() : null)
.put("updated", row.getLocalDateTime("updated") != null ? row.getLocalDateTime("updated").toString() : null);
return pool.preparedQuery(restaurantsSql).execute(io.vertx.sqlclient.Tuple.of(id))
return pool.preparedQuery(restaurantsSql).execute(Tuple.of(id))
.map(restRows -> {
JsonArray restIds = new JsonArray();
restRows.forEach(restRow -> restIds.add(restRow.getInteger("restaurant_id")));
@@ -262,7 +251,6 @@ public class OlapQueryService {
return pool.preparedQuery(sql).execute(Tuple.of(success, queryId)).mapEmpty();
}
// Генерация SQL на основе конфигурации и ID подключения
public Future<String> generateSql(JsonObject config, int dbConnectionId) {
return externalDataBaseService.findById(dbConnectionId)
.compose(conn -> {
@@ -278,9 +266,8 @@ public class OlapQueryService {
}
public boolean isValidTableName(String tableName) {
if (tableName == null) return false;
if (tableName == null) return true;
String trimmed = tableName.trim();
// Первый символ — английская буква, далее буквы или цифры
return trimmed.matches("^[A-Za-z][A-Za-z0-9]*$");
return !trimmed.matches("^[A-Za-z][A-Za-z0-9]*$");
}
}

View File

@@ -11,13 +11,9 @@ import io.vertx.jdbcclient.JDBCPool;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.PoolOptions;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.templates.SqlTemplate;
import io.vertx.sqlclient.Tuple;
import su.xserver.iikocon.handler.AdminHandler;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ExternalDataBaseService {
private final Pool pool;
private final Vertx vertx;
@@ -106,7 +102,7 @@ public class ExternalDataBaseService {
CREATE TABLE IF NOT EXISTS external_database (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) UNIQUE NOT NULL,
type VARCHAR(40) UNIQUE NOT NULL,
type VARCHAR(40) NOT NULL,
host VARCHAR(255) NOT NULL,
port INT NOT NULL,
database VARCHAR(255) NOT NULL,
@@ -120,18 +116,9 @@ public class ExternalDataBaseService {
}
public Future<Void> createDataBase(String name, String type, String host, int port, String database, String user, String password) {
Map<String, Object> params = Map.of(
"name", name,
"type", type,
"host", host,
"port", port,
"database", database,
"user", user,
"password", password
);
return SqlTemplate.forUpdate(pool,
"INSERT INTO external_database (name, type, host, port, database, user, password) VALUES (#{name}, #{type}, #{host}, #{port}, #{database}, #{user}, #{password})")
.execute(params)
String sql = "INSERT INTO external_database (name, type, host, port, database, user, password) VALUES (?, ?, ?, ?, ?, ?, ?)";
return pool.preparedQuery(sql)
.execute(Tuple.of(name, type, host, port, database, user, password))
.mapEmpty();
}
@@ -159,45 +146,47 @@ public class ExternalDataBaseService {
}
public Future<JsonObject> findById(int id) {
return SqlTemplate.forQuery(pool,
"SELECT id, name, type, host, port, database, user, password, created, updated FROM external_database WHERE id = #{id}")
.mapTo(row -> new JsonObject()
.put("id", row.getInteger("id"))
.put("name", row.getString("name"))
.put("type", row.getString("type"))
.put("host", row.getString("host"))
.put("port", row.getInteger("port"))
.put("database", row.getString("database"))
.put("user", row.getString("user"))
.put("password", row.getString("password"))
.put("created", row.getLocalDateTime("created") != null ? row.getLocalDateTime("created").toString() : null)
.put("updated", row.getLocalDateTime("updated") != null ? row.getLocalDateTime("updated").toString() : null))
.execute(Collections.singletonMap("id", id))
.map(rows -> rows.iterator().hasNext() ? rows.iterator().next() : null);
String sql = "SELECT id, name, type, host, port, database, user, password, created, updated FROM external_database WHERE id = ?";
return pool.preparedQuery(sql)
.execute(Tuple.of(id))
.map(rows -> {
if (rows.iterator().hasNext()) {
Row row = rows.iterator().next();
return new JsonObject()
.put("id", row.getInteger("id"))
.put("name", row.getString("name"))
.put("type", row.getString("type"))
.put("host", row.getString("host"))
.put("port", row.getInteger("port"))
.put("database", row.getString("database"))
.put("user", row.getString("user"))
.put("password", row.getString("password"))
.put("created", row.getLocalDateTime("created") != null ? row.getLocalDateTime("created").toString() : null)
.put("updated", row.getLocalDateTime("updated") != null ? row.getLocalDateTime("updated").toString() : null);
} else {
return null;
}
});
}
public Future<Void> updateDataBase(int id, String name, String type, String host, int port, String database, String user, String password) {
Map<String, Object> params = new HashMap<>();
params.put("id", id);
params.put("name", name);
params.put("type", type);
params.put("host", host);
params.put("port", port);
params.put("database", database);
params.put("user", user);
String sql;
Tuple params;
if (password != null && !password.isEmpty()) {
params.put("password", password);
sql = "UPDATE external_database SET name = #{name}, type = #{type}, host = #{host}, port = #{port}, database = #{database}, user = #{user}, password = #{password} WHERE id = #{id}";
sql = "UPDATE external_database SET name = ?, type = ?, host = ?, port = ?, database = ?, user = ?, password = ? WHERE id = ?";
params = Tuple.of(name, type, host, port, database, user, password, id);
} else {
sql = "UPDATE external_database SET name = #{name}, type = #{type}, host = #{host}, port = #{port}, database = #{database}, user = #{user} WHERE id = #{id}";
sql = "UPDATE external_database SET name = ?, type = ?, host = ?, port = ?, database = ?, user = ? WHERE id = ?";
params = Tuple.of(name, type, host, port, database, user, id);
}
return SqlTemplate.forUpdate(pool, sql).execute(params).mapEmpty();
return pool.preparedQuery(sql)
.execute(params)
.mapEmpty();
}
public Future<Void> deleteDataBase(int id) {
return SqlTemplate.forUpdate(pool, "DELETE FROM external_database WHERE id = #{id}")
.execute(Collections.singletonMap("id", id))
return pool.preparedQuery("DELETE FROM external_database WHERE id = ?")
.execute(Tuple.of(id))
.mapEmpty();
}

View File

@@ -5,14 +5,11 @@ import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.templates.SqlTemplate;
import io.vertx.sqlclient.Tuple;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class RestaurantService {
private final Pool pool;
@@ -43,7 +40,7 @@ public class RestaurantService {
CREATE TABLE IF NOT EXISTS restaurants (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) UNIQUE NOT NULL,
login VARCHAR(255) UNIQUE NOT NULL,
login VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
host VARCHAR(255) NOT NULL,
https BOOLEAN DEFAULT FALSE,
@@ -56,15 +53,9 @@ public class RestaurantService {
public Future<Void> createRestaurant(String name, String login, String password, String host, boolean https) {
String hashedPassword = hashPassword(password);
Map<String, Object> params = Map.of(
"name", name,
"login", login,
"password", hashedPassword,
"host", host,
"https", https
);
return SqlTemplate.forUpdate(pool,
"INSERT INTO restaurants (name, login, password, host, https) VALUES (#{name}, #{login}, #{password}, #{host}, #{https})")
String sql = "INSERT INTO restaurants (name, login, password, host, https) VALUES (?, ?, ?, ?, ?)";
Tuple params = Tuple.of(name, login, hashedPassword, host, https);
return pool.preparedQuery(sql)
.execute(params)
.mapEmpty();
}
@@ -91,42 +82,44 @@ public class RestaurantService {
}
public Future<JsonObject> findById(int id) {
return SqlTemplate.forQuery(pool,
"SELECT id, name, login, password, https, host, created, updated FROM restaurants WHERE id = #{id}")
.mapTo(row -> new JsonObject()
.put("id", row.getInteger("id"))
.put("name", row.getString("name"))
.put("login", row.getString("login"))
.put("password", row.getString("password"))
.put("https", row.getBoolean("https"))
.put("host", row.getString("host"))
.put("created", row.getLocalDateTime("created") != null ? row.getLocalDateTime("created").toString() : null)
.put("updated", row.getLocalDateTime("updated") != null ? row.getLocalDateTime("updated").toString() : null))
.execute(Collections.singletonMap("id", id))
.map(rows -> rows.iterator().hasNext() ? rows.iterator().next() : null);
String sql = "SELECT id, name, login, password, https, host, created, updated FROM restaurants WHERE id = ?";
return pool.preparedQuery(sql)
.execute(Tuple.of(id))
.map(rows -> {
Row row = rows.iterator().hasNext() ? rows.iterator().next() : null;
if (row == null) return null;
return new JsonObject()
.put("id", row.getInteger("id"))
.put("name", row.getString("name"))
.put("login", row.getString("login"))
.put("password", row.getString("password"))
.put("https", row.getBoolean("https"))
.put("host", row.getString("host"))
.put("created", row.getLocalDateTime("created") != null ? row.getLocalDateTime("created").toString() : null)
.put("updated", row.getLocalDateTime("updated") != null ? row.getLocalDateTime("updated").toString() : null);
});
}
public Future<Void> updateRestaurant(int id, String name, String login, String password, String host, boolean https) {
Map<String, Object> params = new HashMap<>();
params.put("id", id);
params.put("name", name);
params.put("login", login);
params.put("host", host);
params.put("https", https);
String sql;
Tuple params;
if (password != null && !password.isEmpty()) {
String hashedPassword = hashPassword(password);
params.put("password", hashedPassword);
sql = "UPDATE restaurants SET name = #{name}, login = #{login}, password = #{password}, host = #{host}, https = #{https} WHERE id = #{id}";
sql = "UPDATE restaurants SET name = ?, login = ?, password = ?, host = ?, https = ? WHERE id = ?";
params = Tuple.of(name, login, hashedPassword, host, https, id);
} else {
sql = "UPDATE restaurants SET name = #{name}, login = #{login}, host = #{host}, https = #{https} WHERE id = #{id}";
sql = "UPDATE restaurants SET name = ?, login = ?, host = ?, https = ? WHERE id = ?";
params = Tuple.of(name, login, host, https, id);
}
return SqlTemplate.forUpdate(pool, sql).execute(params).mapEmpty();
return pool.preparedQuery(sql)
.execute(params)
.mapEmpty();
}
public Future<Void> deleteRestaurant(int id) {
return SqlTemplate.forUpdate(pool, "DELETE FROM restaurants WHERE id = #{id}")
.execute(Collections.singletonMap("id", id))
String sql = "DELETE FROM restaurants WHERE id = ?";
return pool.preparedQuery(sql)
.execute(Tuple.of(id))
.mapEmpty();
}
}

View File

@@ -4,10 +4,10 @@ import io.vertx.core.Future;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.templates.SqlTemplate;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.Tuple;
import java.util.List;
import java.util.Map;
public class SettingsService {
private final Pool pool;
@@ -136,16 +136,20 @@ public class SettingsService {
}
public Future<String> get(String key) {
return SqlTemplate.forQuery(pool, "SELECT setting_value FROM app_settings WHERE setting_key = #{key}")
.execute(Map.of("key", key))
.map(rows -> rows.iterator().hasNext() ? rows.iterator().next().getString("setting_value") : null);
String sql = "SELECT setting_value FROM app_settings WHERE setting_key = ?";
return pool.preparedQuery(sql)
.execute(Tuple.of(key))
.map(rows -> {
Row row = rows.iterator().hasNext() ? rows.iterator().next() : null;
return row != null ? row.getString("setting_value") : null;
});
}
public Future<Void> set(String key, String value) {
return SqlTemplate.forUpdate(pool,
"INSERT INTO app_settings (setting_key, setting_value) VALUES (#{key}, #{value}) " +
"ON DUPLICATE KEY UPDATE setting_value = #{value}")
.execute(Map.of("key", key, "value", value))
String sql = "INSERT INTO app_settings (setting_key, setting_value) VALUES (?, ?) " +
"ON DUPLICATE KEY UPDATE setting_value = ?";
return pool.preparedQuery(sql)
.execute(Tuple.of(key, value, value))
.mapEmpty();
}

View File

@@ -6,7 +6,6 @@ import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.Tuple;
import io.vertx.sqlclient.templates.SqlTemplate;
import org.mindrot.jbcrypt.BCrypt;
import java.util.*;
@@ -44,18 +43,9 @@ public class UserService {
public Future<Void> createUser(String login, String email, String password, String ip, boolean active, String role) {
String hash = BCrypt.hashpw(password, BCrypt.gensalt());
Map<String, Object> params = Map.of(
"login", login,
"email", email,
"password", hash,
"ip", ip,
"active", active,
"role", role
);
return SqlTemplate.forUpdate(pool,
"INSERT INTO users (login, email, password, ip, active, role) VALUES (#{login}, #{email}, #{password}, #{ip}, #{active}, #{role})")
.execute(params)
.mapEmpty();
String sql = "INSERT INTO users (login, email, password, ip, active, role) VALUES (?, ?, ?, ?, ?, ?)";
Tuple params = Tuple.of(login, email, hash, ip, active, role);
return pool.preparedQuery(sql).execute(params).mapEmpty();
}
public Future<Void> createUser(String login, String email, String password, String ip, boolean active) {
@@ -67,8 +57,9 @@ public class UserService {
}
public Future<Void> setActive(int id, boolean active) {
return SqlTemplate.forUpdate(pool, "UPDATE users SET active = #{active} WHERE id = #{id}")
.execute(Map.of("id", id, "active", active)).mapEmpty();
return pool.preparedQuery("UPDATE users SET active = ? WHERE id = ?")
.execute(Tuple.of(active, id))
.mapEmpty();
}
public Future<JsonObject> findByLoginOrEmail(String loginOrEmail) {
@@ -106,24 +97,30 @@ public class UserService {
}
public Future<Void> updateUser(int id, String login, String email, String password, String ip, String role) {
Map<String, Object> params = new HashMap<>();
params.put("id", id);
params.put("login", login);
params.put("email", email);
params.put("ip", ip);
if (role != null) params.put("role", role);
List<Object> values = new ArrayList<>();
values.add(login);
values.add(email);
values.add(ip);
if (role != null) {
values.add(role);
}
String sql;
if (password != null && !password.isEmpty()) {
String hash = BCrypt.hashpw(password, BCrypt.gensalt());
params.put("password", hash);
sql = "UPDATE users SET login = #{login}, email = #{email}, password = #{password}, ip = #{ip}"
+ (role != null ? ", role = #{role}" : "") + " WHERE id = #{id}";
sql = "UPDATE users SET login = ?, email = ?, password = ?, ip = ?" +
(role != null ? ", role = ?" : "") + " WHERE id = ?";
values.add(2, hash);
} else {
sql = "UPDATE users SET login = #{login}, email = #{email}, ip = #{ip}"
+ (role != null ? ", role = #{role}" : "") + " WHERE id = #{id}";
sql = "UPDATE users SET login = ?, email = ?, ip = ?" +
(role != null ? ", role = ?" : "") + " WHERE id = ?";
}
return SqlTemplate.forUpdate(pool, sql).execute(params).mapEmpty();
values.add(id); // для WHERE
return pool.preparedQuery(sql)
.execute(Tuple.tuple(values))
.mapEmpty();
}
public Future<Void> updateUserIp(int userId, String ip) {
@@ -133,54 +130,60 @@ public class UserService {
}
public Future<Void> deleteUser(int id) {
return SqlTemplate.forUpdate(pool, "DELETE FROM users WHERE id = #{id}")
.execute(Collections.singletonMap("id", id))
return pool.preparedQuery("DELETE FROM users WHERE id = ?")
.execute(Tuple.of(id))
.mapEmpty();
}
public Future<JsonObject> getProfile(int userId) {
return SqlTemplate.forQuery(pool,
"SELECT id, login, email, role, language, ip, created, updated FROM users WHERE id = #{id}")
.mapTo(row -> new JsonObject()
.put("id", row.getInteger("id"))
.put("login", row.getString("login"))
.put("email", row.getString("email"))
.put("role", row.getString("role"))
.put("language", row.getString("language"))
.put("ip", row.getString("ip"))
.put("created", row.getLocalDateTime("created") != null ? row.getLocalDateTime("created").toString() : null)
.put("updated", row.getLocalDateTime("updated") != null ? row.getLocalDateTime("updated").toString() : null))
.execute(Map.of("id", userId))
.map(rows -> rows.iterator().hasNext() ? rows.iterator().next() : null);
String sql = "SELECT id, login, email, role, language, ip, created, updated FROM users WHERE id = ?";
return pool.preparedQuery(sql)
.execute(Tuple.of(userId))
.map(rows -> {
if (rows.size() == 0) return null;
Row row = rows.iterator().next();
return new JsonObject()
.put("id", row.getInteger("id"))
.put("login", row.getString("login"))
.put("email", row.getString("email"))
.put("role", row.getString("role"))
.put("language", row.getString("language"))
.put("ip", row.getString("ip"))
.put("created", row.getLocalDateTime("created") != null ? row.getLocalDateTime("created").toString() : null)
.put("updated", row.getLocalDateTime("updated") != null ? row.getLocalDateTime("updated").toString() : null);
});
}
public Future<Void> updateProfile(int userId, String email, String password, String language) {
Map<String, Object> params = new HashMap<>();
params.put("id", userId);
List<String> setClauses = new ArrayList<>();
List<Object> values = new ArrayList<>();
if (email != null) {
setClauses.add("email = #{email}");
params.put("email", email);
setClauses.add("email = ?");
values.add(email);
}
if (password != null && !password.isEmpty()) {
String hash = BCrypt.hashpw(password, BCrypt.gensalt());
setClauses.add("password = #{password}");
params.put("password", hash);
setClauses.add("password = ?");
values.add(hash);
}
if (language != null) {
setClauses.add("language = #{language}");
params.put("language", language);
setClauses.add("language = ?");
values.add(language);
}
if (setClauses.isEmpty()) {
return Future.succeededFuture();
}
String sql = "UPDATE users SET " + String.join(", ", setClauses) + " WHERE id = #{id}";
return SqlTemplate.forUpdate(pool, sql).execute(params).mapEmpty();
values.add(userId);
String sql = "UPDATE users SET " + String.join(", ", setClauses) + " WHERE id = ?";
return pool.preparedQuery(sql)
.execute(Tuple.tuple(values))
.mapEmpty();
}
public boolean checkPassword(String plain, String hash) {

View File

@@ -18,13 +18,5 @@ public class DateRangeSetup {
System.out.println("dateFrom=" + formattedDateFrom);
System.out.println("dateTo=" + formattedDateTo);
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
}
}