summaryrefslogtreecommitdiff
path: root/src/main/java/com/keuin/blame
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/keuin/blame')
-rw-r--r--src/main/java/com/keuin/blame/command/BlameBlockCommand.java4
-rw-r--r--src/main/java/com/keuin/blame/lookup/QueryExecutor.java62
-rw-r--r--src/main/java/com/keuin/blame/util/TablePrinter.java40
3 files changed, 71 insertions, 35 deletions
diff --git a/src/main/java/com/keuin/blame/command/BlameBlockCommand.java b/src/main/java/com/keuin/blame/command/BlameBlockCommand.java
index 695f9ad..b10a977 100644
--- a/src/main/java/com/keuin/blame/command/BlameBlockCommand.java
+++ b/src/main/java/com/keuin/blame/command/BlameBlockCommand.java
@@ -82,6 +82,8 @@ public class BlameBlockCommand {
timeRange *= amplifier;
if (timeRange < 0)
return FAILED;
+ // convert to maximum unix millis
+ timeRange = System.currentTimeMillis() - timeRange * 1000L;
}
int amountLimit;
@@ -95,7 +97,7 @@ public class BlameBlockCommand {
amountLimit = BlameLimitCommand.DEFAULT_LOOKUP_LIMIT;
}
- Blame.queryExecutor.byBlockPos(world, x, y, z, (msg) ->
+ Blame.queryExecutor.byBlockPos(world, x, y, z, timeRange, amountLimit, (msg) ->
context.getSource().sendFeedback(msg, false));
return SUCCESS;
diff --git a/src/main/java/com/keuin/blame/lookup/QueryExecutor.java b/src/main/java/com/keuin/blame/lookup/QueryExecutor.java
index 8522de7..7acac0a 100644
--- a/src/main/java/com/keuin/blame/lookup/QueryExecutor.java
+++ b/src/main/java/com/keuin/blame/lookup/QueryExecutor.java
@@ -1,13 +1,11 @@
package com.keuin.blame.lookup;
-import com.clickhouse.client.ClickHouseParameterizedQuery;
import com.clickhouse.data.ClickHouseFormat;
-import com.clickhouse.data.value.ClickHouseLongValue;
-import com.clickhouse.data.value.ClickHouseStringValue;
import com.keuin.blame.data.enums.ActionType;
import com.keuin.blame.util.DatabaseUtil;
import com.keuin.blame.util.TablePrinter;
import net.minecraft.text.LiteralText;
+import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -23,27 +21,51 @@ public class QueryExecutor {
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- public void byBlockPos(String world, long x, long y, long z, Consumer<Text> callback) {
+ private String getSQL(
+ String world,
+ long x, long y, long z,
+ long timeRange,
+ int maxCount
+ ) {
+ // ClickHouse driver's parameterized SQL generator is a piece of shit.
+ // I won't use that. Use string interpolation instead.
+ var sql = "select subject_id, object_id, action_type, ts";
+ sql += " from " + escape(DatabaseUtil.DB_CONFIG.table());
+ sql += " where subject_world=%s and object_x=%d and object_y=%d and object_z=%d".formatted(
+ escape(world), x, y, z
+ );
+ if (timeRange > 0) {
+ sql += " and ts>=" + timeRange;
+ }
+ if (maxCount > 0) {
+ sql += " limit " + maxCount;
+ }
+ return sql;
+ }
+
+ private static String escape(String s) {
+ return "'" + s.replace("\\", "\\\\").replace("'", "\\'") + "'";
+ }
+
+ public void byBlockPos(
+ String world,
+ long x, long y, long z,
+ long timeRange,
+ int maxCount,
+ Consumer<Text> callback
+ ) {
var server = DatabaseUtil.getServer();
- var stmt = ClickHouseParameterizedQuery.of(server.getConfig(),
- "select subject_id, object_id, action_type, ts " +
- "from :table where subject_world=:world and object_x=:x and object_y=:y and object_z=:z");
+ var sql = getSQL(world, x, y, z, timeRange, maxCount);
+ logger.info("SQL: " + sql);
try (var client = DatabaseUtil.getClient(server)) {
var resp = client.read(server)
.format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
- .query(stmt)
- .params(
- ClickHouseStringValue.of(DatabaseUtil.DB_CONFIG.table()),
- ClickHouseStringValue.of(world),
- ClickHouseLongValue.of(x),
- ClickHouseLongValue.of(y),
- ClickHouseLongValue.of(z)
- )
+ .query(sql)
.execute()
.get();
int cnt = 0;
- var sb = new StringBuilder();
- sb.append(String.format("Result for block at %s (%d, %d, %d):\n", world, x, y, z));
+ MutableText t = new LiteralText("");
+ t = t.append(String.format("Result for block at %s (%d, %d, %d):\n", world, x, y, z));
final int columns = 4;
var table = new TablePrinter(columns);
table.add(new TablePrinter.Row("Player", "Object", "Action", "Time"));
@@ -57,9 +79,9 @@ public class QueryExecutor {
table.add(new TablePrinter.Row(player, obj, actionType, time));
cnt++;
}
- sb.append(table);
- sb.append(String.format("%d records in total.", cnt));
- callback.accept(new LiteralText(sb.toString()));
+ t = t.append(table.build());
+ t = t.append(String.format("%d records in total.", cnt));
+ callback.accept(t);
} catch (Exception ex) {
logger.error("Query block failed", ex);
callback.accept(new LiteralText("Query failed: " + ex));
diff --git a/src/main/java/com/keuin/blame/util/TablePrinter.java b/src/main/java/com/keuin/blame/util/TablePrinter.java
index 8b8eca3..e296e3c 100644
--- a/src/main/java/com/keuin/blame/util/TablePrinter.java
+++ b/src/main/java/com/keuin/blame/util/TablePrinter.java
@@ -1,7 +1,11 @@
package com.keuin.blame.util;
+import net.minecraft.text.LiteralText;
+import net.minecraft.text.MutableText;
+import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
+
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
@@ -12,7 +16,8 @@ public class TablePrinter {
private Function<String, Integer> widthSupplier = (String::length);
- private final int BORDER = 1;
+ private List<Formatting> colors = List.of(
+ Formatting.RED, Formatting.GOLD, Formatting.GREEN, Formatting.BLUE, Formatting.DARK_PURPLE);
public TablePrinter(int columns) {
this.columns = columns;
@@ -30,8 +35,12 @@ public class TablePrinter {
return this;
}
- @Override
- public String toString() {
+ private Formatting getColor(int i) {
+ return colors.get(i % colors.size());
+ }
+
+ public Text build() {
+ final String SEPARATOR = ".";
var maxWidths = new int[columns];
for (var r : rows) {
for (int i = 0; i < r.row.length; i++) {
@@ -39,27 +48,30 @@ public class TablePrinter {
maxWidths[i] = Math.max(maxWidths[i], len);
}
}
- var sb = new StringBuilder();
+ MutableText t = new LiteralText("");
for (var r : rows) {
var i = 0;
for (String s : r.row) {
- sb.append('|');
- sb.append(' ');
- sb.append(s);
+ t = t.append(new LiteralText(SEPARATOR + " "));
+
var n = maxWidths[i] - s.length();
if (n > 0) {
- sb.append(" ".repeat(n));
+ t = t.append(" ".repeat(n / 2));
+ }
+ t = t.append(new LiteralText(s).formatted(getColor(i)));
+ if (n > 0) {
+ t = t.append(" ".repeat(n - n / 2));
}
- sb.append(' ');
+ t = t.append(" ");
i++;
}
if (r.row.length == 0) {
- sb.append('|');
+ t = t.append(SEPARATOR);
}
- sb.append("|");
- sb.append('\n');
+ t = t.append(SEPARATOR);
+ t = t.append("\n");
}
- return sb.toString();
+ return t;
}
public static class Row {