up
This commit is contained in:
@@ -552,14 +552,31 @@ public class MainVerticle extends AbstractVerticle {
|
||||
JsonArray restaurantIdsArray = body.getJsonArray("restaurantIds", new JsonArray());
|
||||
List<Integer> restaurantIds = restaurantIdsArray.stream().map(id -> (Integer) id).collect(Collectors.toList());
|
||||
|
||||
// Получаем active: сначала из тела, иначе из конфига, иначе true
|
||||
Boolean active = body.getBoolean("active");
|
||||
if (active == null && config != null) active = config.getBoolean("active", true);
|
||||
if (active == null) active = true;
|
||||
|
||||
if (name == null || dbConnectionId == null || config == null) {
|
||||
rc.response().setStatusCode(400).end("Missing required fields");
|
||||
return;
|
||||
}
|
||||
|
||||
// Сначала генерируем SQL
|
||||
String tableName = config.getString("tableName");
|
||||
|
||||
if (tableName.isEmpty()) {
|
||||
rc.response().setStatusCode(400).end("Missing required fields");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!olapQueryService.isValidTableName(tableName)) {
|
||||
rc.response().setStatusCode(400).end("Invalid tableName: must start with a letter and contain only letters and digits");
|
||||
return;
|
||||
}
|
||||
|
||||
Boolean finalActive = active;
|
||||
olapQueryService.generateSql(config, dbConnectionId)
|
||||
.compose(sql -> olapQueryService.createQuery(name, dbConnectionId, config, restaurantIds, sql))
|
||||
.compose(sql -> olapQueryService.createQuery(name, dbConnectionId, config, restaurantIds, sql, finalActive))
|
||||
.onSuccess(id -> rc.response().setStatusCode(201).putHeader("Content-Type", "application/json").end(new JsonObject().put("id", id).encode()))
|
||||
.onFailure(err -> rc.response().setStatusCode(500).end(err.getMessage()));
|
||||
});
|
||||
@@ -573,13 +590,30 @@ public class MainVerticle extends AbstractVerticle {
|
||||
JsonArray restaurantIdsArray = body.getJsonArray("restaurantIds", new JsonArray());
|
||||
List<Integer> restaurantIds = restaurantIdsArray.stream().map(v -> (Integer) v).collect(Collectors.toList());
|
||||
|
||||
Boolean active = body.getBoolean("active");
|
||||
if (active == null && config != null) active = config.getBoolean("active", true);
|
||||
if (active == null) active = true;
|
||||
|
||||
if (name == null || dbConnectionId == null || config == null) {
|
||||
rc.response().setStatusCode(400).end("Missing required fields");
|
||||
return;
|
||||
}
|
||||
|
||||
String tableName = config.getString("tableName");
|
||||
|
||||
if (tableName.isEmpty()) {
|
||||
rc.response().setStatusCode(400).end("Missing required fields");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!olapQueryService.isValidTableName(tableName)) {
|
||||
rc.response().setStatusCode(400).end("Invalid tableName: must start with a letter and contain only letters and digits");
|
||||
return;
|
||||
}
|
||||
|
||||
Boolean finalActive = active;
|
||||
olapQueryService.generateSql(config, dbConnectionId)
|
||||
.compose(sql -> olapQueryService.updateQuery(id, name, dbConnectionId, config, restaurantIds, sql))
|
||||
.compose(sql -> olapQueryService.updateQuery(id, name, dbConnectionId, config, restaurantIds, sql, finalActive))
|
||||
.onSuccess(v -> rc.response().end())
|
||||
.onFailure(err -> rc.response().setStatusCode(500).end(err.getMessage()));
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ 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.Tuple;
|
||||
import io.vertx.sqlclient.templates.SqlTemplate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -33,6 +34,9 @@ public class OlapQueryService {
|
||||
config_json JSON NOT NULL,
|
||||
full_config_json JSON NOT NULL,
|
||||
sql_text TEXT,
|
||||
active BOOLEAN NOT NULL DEFAULT true,
|
||||
last_run TIMESTAMP NULL,
|
||||
last_run_success BOOLEAN NULL,
|
||||
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (db_connection_id) REFERENCES external_database(id) ON DELETE RESTRICT
|
||||
@@ -56,16 +60,17 @@ public class OlapQueryService {
|
||||
|
||||
// Создание запроса
|
||||
public Future<Integer> createQuery(String name, int dbConnectionId, JsonObject config,
|
||||
List<Integer> restaurantIds, String generatedSql) {
|
||||
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 : ""
|
||||
"sql_text", generatedSql != null ? generatedSql : "",
|
||||
"active", active
|
||||
);
|
||||
String sql = "INSERT INTO olap_queries (name, db_connection_id, config_json, full_config_json, sql_text) VALUES (#{name}, #{db_connection_id}, #{config_json}, #{full_config_json}, #{sql_text})";
|
||||
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)
|
||||
.compose(rows -> getLastInsertId())
|
||||
@@ -73,7 +78,7 @@ public class OlapQueryService {
|
||||
}
|
||||
|
||||
public Future<Void> updateQuery(int id, String name, int dbConnectionId, JsonObject config,
|
||||
List<Integer> restaurantIds, String generatedSql) {
|
||||
List<Integer> restaurantIds, String generatedSql, boolean active) {
|
||||
JsonObject fullConfig = generateFullIikoJson(config);
|
||||
Map<String, Object> params = Map.of(
|
||||
"id", id,
|
||||
@@ -81,15 +86,14 @@ public class OlapQueryService {
|
||||
"db_connection_id", dbConnectionId,
|
||||
"config_json", config.encode(),
|
||||
"full_config_json", fullConfig.encode(),
|
||||
"sql_text", generatedSql != null ? generatedSql : ""
|
||||
"sql_text", generatedSql != null ? generatedSql : "",
|
||||
"active", active
|
||||
);
|
||||
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} WHERE id = #{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)
|
||||
.compose(v -> {
|
||||
return pool.query("DELETE FROM olap_query_restaurants WHERE query_id = " + id).execute()
|
||||
.compose(del -> linkRestaurants(id, restaurantIds));
|
||||
}).mapEmpty();
|
||||
.compose(v -> pool.query("DELETE FROM olap_query_restaurants WHERE query_id = " + id).execute()
|
||||
.compose(del -> linkRestaurants(id, restaurantIds))).mapEmpty();
|
||||
}
|
||||
|
||||
public JsonObject generateFullIikoJson(JsonObject clientConfig) {
|
||||
@@ -139,14 +143,13 @@ public class OlapQueryService {
|
||||
// Добавляем системные
|
||||
allFilters.mergeIn(systemFilters);
|
||||
|
||||
JsonObject result = new JsonObject()
|
||||
return new JsonObject()
|
||||
.put("reportType", reportType)
|
||||
.put("buildSummary", buildSummary)
|
||||
.put("groupByRowFields", rowFields)
|
||||
.put("groupByColFields", columnFields)
|
||||
.put("aggregateFields", valueFields)
|
||||
.put("filters", allFilters);
|
||||
return result;
|
||||
}
|
||||
|
||||
private JsonObject buildDateFilter(String reportType, String dateToStr, int daysBack) {
|
||||
@@ -195,36 +198,38 @@ public class OlapQueryService {
|
||||
// Получить все запросы (без config_json, для списка)
|
||||
public Future<JsonArray> getAllQueries() {
|
||||
String sql = """
|
||||
SELECT q.id, q.name, q.db_connection_id, q.created, q.updated,
|
||||
GROUP_CONCAT(r.name SEPARATOR ', ') AS restaurants,
|
||||
dc.name AS db_connection_name
|
||||
FROM olap_queries q
|
||||
LEFT JOIN olap_query_restaurants qr ON q.id = qr.query_id
|
||||
LEFT JOIN restaurants r ON qr.restaurant_id = r.id
|
||||
LEFT JOIN external_database dc ON q.db_connection_id = dc.id
|
||||
GROUP BY q.id
|
||||
ORDER BY q.id DESC
|
||||
""";
|
||||
SELECT q.id, q.name, q.db_connection_id, q.active, q.last_run, q.last_run_success, q.created, q.updated,
|
||||
GROUP_CONCAT(r.name SEPARATOR ', ') AS restaurants,
|
||||
dc.name AS db_connection_name
|
||||
FROM olap_queries q
|
||||
LEFT JOIN olap_query_restaurants qr ON q.id = qr.query_id
|
||||
LEFT JOIN restaurants r ON qr.restaurant_id = r.id
|
||||
LEFT JOIN external_database dc ON q.db_connection_id = dc.id
|
||||
GROUP BY q.id
|
||||
ORDER BY q.id DESC
|
||||
""";
|
||||
return pool.query(sql).execute()
|
||||
.map(rows -> {
|
||||
JsonArray arr = new JsonArray();
|
||||
rows.forEach(row -> {
|
||||
arr.add(new JsonObject()
|
||||
.put("id", row.getInteger("id"))
|
||||
.put("name", row.getString("name"))
|
||||
.put("dbConnectionId", row.getInteger("db_connection_id"))
|
||||
.put("dbConnectionName", row.getString("db_connection_name"))
|
||||
.put("restaurants", row.getString("restaurants") != null ? row.getString("restaurants") : "")
|
||||
.put("created", row.getLocalDateTime("created") != null ? row.getLocalDateTime("created").toString() : null)
|
||||
.put("updated", row.getLocalDateTime("updated") != null ? row.getLocalDateTime("updated").toString() : null));
|
||||
});
|
||||
rows.forEach(row -> arr.add(new JsonObject()
|
||||
.put("id", row.getInteger("id"))
|
||||
.put("name", row.getString("name"))
|
||||
.put("dbConnectionId", row.getInteger("db_connection_id"))
|
||||
.put("dbConnectionName", row.getString("db_connection_name"))
|
||||
.put("restaurants", row.getString("restaurants") != null ? row.getString("restaurants") : "")
|
||||
.put("active", row.getBoolean("active"))
|
||||
.put("lastRun", row.getLocalDateTime("last_run") != null ? row.getLocalDateTime("last_run").toString() : null)
|
||||
.put("lastRunSuccess", row.getBoolean("last_run_success"))
|
||||
.put("created", row.getLocalDateTime("created") != null ? row.getLocalDateTime("created").toString() : null)
|
||||
.put("updated", row.getLocalDateTime("updated") != null ? row.getLocalDateTime("updated").toString() : null)));
|
||||
return arr;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Получить один запрос с полной конфигурацией
|
||||
public Future<JsonObject> getQueryById(int id) {
|
||||
String querySql = "SELECT id, name, db_connection_id, config_json, sql_text, created, updated FROM olap_queries WHERE 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))
|
||||
@@ -237,6 +242,7 @@ public class OlapQueryService {
|
||||
.put("dbConnectionId", row.getInteger("db_connection_id"))
|
||||
.put("config", new JsonObject(row.getString("config_json")))
|
||||
.put("sql", row.getString("sql_text"))
|
||||
.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);
|
||||
|
||||
@@ -250,6 +256,12 @@ public class OlapQueryService {
|
||||
});
|
||||
}
|
||||
|
||||
// Метод для обновления статуса выполнения
|
||||
public Future<Void> updateRunStatus(int queryId, boolean success) {
|
||||
String sql = "UPDATE olap_queries SET last_run = NOW(), last_run_success = ? WHERE id = ?";
|
||||
return pool.preparedQuery(sql).execute(Tuple.of(success, queryId)).mapEmpty();
|
||||
}
|
||||
|
||||
// Генерация SQL на основе конфигурации и ID подключения
|
||||
public Future<String> generateSql(JsonObject config, int dbConnectionId) {
|
||||
return externalDataBaseService.findById(dbConnectionId)
|
||||
@@ -264,4 +276,11 @@ public class OlapQueryService {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isValidTableName(String tableName) {
|
||||
if (tableName == null) return false;
|
||||
String trimmed = tableName.trim();
|
||||
// Первый символ — английская буква, далее буквы или цифры
|
||||
return trimmed.matches("^[A-Za-z][A-Za-z0-9]*$");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user