Skip to content

Commit 31f4190

Browse files
committed
refactor: helper for duration in seconds calculation
spotless fixes, helper for calculating duration in seconds between datetime fields to be more compliant with code quality tests
1 parent 70fafef commit 31f4190

File tree

1 file changed

+46
-27
lines changed

1 file changed

+46
-27
lines changed

application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadStatsCommand.java

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import net.dv8tion.jda.api.interactions.commands.OptionType;
66
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
77
import org.jooq.DSLContext;
8+
import org.jooq.Field;
89
import org.jooq.OrderField;
910
import org.jooq.Record1;
1011

@@ -38,6 +39,14 @@
3839
public class HelpThreadStatsCommand extends SlashCommandAdapter {
3940
public static final String COMMAND_NAME = "help-thread-stats";
4041
public static final String DURATION_OPTION = "duration-option";
42+
private static final String TOTAL_CREATED_FIELD = "total_created";
43+
private static final String OPEN_NOW_ALIAS = "open_now";
44+
private static final String GHOST_NOW_ALIAS = "ghost_count";
45+
private static final String AVERAGE_PARTICIPANTS_ALIAS = "avg_parts";
46+
private static final String AVERAGE_MESSAGE_COUNT_ALIAS = "avg_msgs";
47+
private static final String AVERAGE_THREAD_DURATION_IN_SECONDS_ALIAS = "avg_sec";
48+
private static final String MINIMUM_THREAD_DURATION_IN_SECONDS_ALIAS = "min_sec";
49+
private static final String MAXIMUM_THREAD_DURATION_IN_SECONDS_ALIAS = "max_sec";
4150

4251
private final Database database;
4352

@@ -72,36 +81,33 @@ public void onSlashCommand(SlashCommandInteractionEvent event) {
7281

7382
database.read(context -> {
7483
var statsRecord = context
75-
.select(count().as("total_created"), count()
84+
.select(count().as(TOTAL_CREATED_FIELD), count()
7685
.filterWhere(
7786
HELP_THREADS.TICKET_STATUS.eq(HelpSystemHelper.TicketStatus.ACTIVE.val))
78-
.as("open_now"),
79-
count().filterWhere(HELP_THREADS.PARTICIPANTS.eq(1)).as("ghost_count"),
80-
avg(HELP_THREADS.PARTICIPANTS).as("avg_parts"),
81-
avg(HELP_THREADS.MESSAGE_COUNT).as("avg_msgs"),
82-
avg(field("unixepoch({0}) - unixepoch({1})", Double.class,
83-
HELP_THREADS.CLOSED_AT, HELP_THREADS.CREATED_AT))
84-
.as("avg_sec"),
85-
min(field("unixepoch({0}) - unixepoch({1})", Double.class,
86-
HELP_THREADS.CLOSED_AT, HELP_THREADS.CREATED_AT))
87-
.as("min_sec"),
88-
max(field("unixepoch({0}) - unixepoch({1})", Double.class,
89-
HELP_THREADS.CLOSED_AT, HELP_THREADS.CREATED_AT))
90-
.as("max_sec"))
87+
.as(OPEN_NOW_ALIAS),
88+
count().filterWhere(HELP_THREADS.PARTICIPANTS.eq(1)).as(GHOST_NOW_ALIAS),
89+
avg(HELP_THREADS.PARTICIPANTS).as(AVERAGE_PARTICIPANTS_ALIAS),
90+
avg(HELP_THREADS.MESSAGE_COUNT).as(AVERAGE_MESSAGE_COUNT_ALIAS),
91+
avg(durationInSeconds(HELP_THREADS.CLOSED_AT, HELP_THREADS.CREATED_AT))
92+
.as(AVERAGE_THREAD_DURATION_IN_SECONDS_ALIAS),
93+
min(durationInSeconds(HELP_THREADS.CLOSED_AT, HELP_THREADS.CREATED_AT))
94+
.as(MINIMUM_THREAD_DURATION_IN_SECONDS_ALIAS),
95+
max(durationInSeconds(HELP_THREADS.CLOSED_AT, HELP_THREADS.CREATED_AT))
96+
.as(MAXIMUM_THREAD_DURATION_IN_SECONDS_ALIAS))
9197
.from(HELP_THREADS)
9298
.where(HELP_THREADS.CREATED_AT.ge(startDate))
9399
.fetchOne();
94100

95-
if (statsRecord == null || statsRecord.get("total_created", Integer.class) == 0) {
101+
if (statsRecord == null || statsRecord.get(TOTAL_CREATED_FIELD, Integer.class) == 0) {
96102
event.getHook()
97103
.editOriginal("No stats available for the last " + days + " days.")
98104
.queue();
99105
return null;
100106
}
101107

102-
int totalCreated = statsRecord.get("total_created", Integer.class);
103-
int openThreads = statsRecord.get("open_now", Integer.class);
104-
long ghostThreads = statsRecord.get("ghost_count", Number.class).longValue();
108+
int totalCreated = statsRecord.get(TOTAL_CREATED_FIELD, Integer.class);
109+
int openThreads = statsRecord.get(OPEN_NOW_ALIAS, Integer.class);
110+
long ghostThreads = statsRecord.get(GHOST_NOW_ALIAS, Number.class).longValue();
105111

106112
double rawResRate =
107113
totalCreated > 0 ? ((double) (totalCreated - ghostThreads) / totalCreated) * 100
@@ -124,27 +130,32 @@ public void onSlashCommand(SlashCommandInteractionEvent event) {
124130
Objects.requireNonNull(event.getGuild()).getIconUrl());
125131

126132
embed.addField("📝 THREAD ACTIVITY",
127-
"Created: `%d`\nCurrently Open: `%d`\nResponse Rate: %.1f%%\nPeak Hours: `%s`"
133+
"Created: `%d`%nCurrently Open: `%d`%nResponse Rate: %.1f%%%nPeak Hours: `%s`"
128134
.formatted(totalCreated, openThreads, rawResRate, peakHourRange),
129135
false);
130136

131137
embed.addField("💬 ENGAGEMENT",
132-
"Avg Messages: `%s`\nAvg Helpers: `%s`\nUnanswered (Ghost): `%d`".formatted(
133-
formatDouble(Objects.requireNonNull(statsRecord.get("avg_msgs"))),
134-
formatDouble(Objects.requireNonNull(statsRecord.get("avg_parts"))),
138+
"Avg Messages: `%s`%nAvg Helpers: `%s`%nUnanswered (Ghost): `%d`".formatted(
139+
formatDouble(Objects
140+
.requireNonNull(statsRecord.get(AVERAGE_MESSAGE_COUNT_ALIAS))),
141+
formatDouble(Objects
142+
.requireNonNull(statsRecord.get(AVERAGE_PARTICIPANTS_ALIAS))),
135143
ghostThreads),
136144
false);
137145

138146
embed.addField("🏷️ TAG ACTIVITY",
139-
"Most Used: `%s`\nMost Active: `%s`\nNeeds Love: `%s`".formatted(highVolumeTag,
147+
"Most Used: `%s`%nMost Active: `%s`%nNeeds Love: `%s`".formatted(highVolumeTag,
140148
highActivityTag, lowActivityTag),
141149
false);
142150

143151
embed.addField("⚡ RESOLUTION SPEED",
144-
"Average: `%s`\nFastest: `%s`\nSlowest: `%s`".formatted(
145-
smartFormat(statsRecord.get("avg_sec", Double.class)),
146-
smartFormat(statsRecord.get("min_sec", Double.class)),
147-
smartFormat(statsRecord.get("max_sec", Double.class))),
152+
"Average: `%s`%nFastest: `%s`%nSlowest: `%s`".formatted(
153+
smartFormat(statsRecord.get(AVERAGE_THREAD_DURATION_IN_SECONDS_ALIAS,
154+
Double.class)),
155+
smartFormat(statsRecord.get(MINIMUM_THREAD_DURATION_IN_SECONDS_ALIAS,
156+
Double.class)),
157+
smartFormat(statsRecord.get(MAXIMUM_THREAD_DURATION_IN_SECONDS_ALIAS,
158+
Double.class))),
148159
false);
149160

150161
event.getHook().editOriginalEmbeds(embed.build()).queue();
@@ -208,4 +219,12 @@ private String smartFormat(Double seconds) {
208219
private String formatDouble(Object val) {
209220
return val instanceof Number num ? "%.2f".formatted(num.doubleValue()) : "0.00";
210221
}
222+
223+
/**
224+
* Calculates the duration in seconds between two timestamp fields. Uses SQLite unixepoch for
225+
* conversion.
226+
*/
227+
private Field<Double> durationInSeconds(Field<Instant> end, Field<Instant> start) {
228+
return field("unixepoch({0}) - unixepoch({1})", Double.class, end, start);
229+
}
211230
}

0 commit comments

Comments
 (0)