From e34096b897fdba2bbc1518884dd0f4f405816482 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Thu, 15 Jan 2026 09:09:16 +0000
Subject: [PATCH] Optimize getMainMedal to use a JOIN query
- Replaces sequential queries (N+1) with a single INNER JOIN in SQLManager.getMainMedal
- Adds JUnit 5 and Mockito dependencies for testing
- Refactors SQLManager to support dependency injection for testing
- Adds SQLManagerTest to verify the optimization and correctness
---
modules/MedalCabinet/pom.xml | 18 +++++
.../mcatk/medalcabinet/sql/SQLManager.java | 17 +++-
.../medalcabinet/sql/SQLManagerTest.java | 79 +++++++++++++++++++
3 files changed, 112 insertions(+), 2 deletions(-)
create mode 100644 modules/MedalCabinet/src/test/java/com/mcatk/medalcabinet/sql/SQLManagerTest.java
diff --git a/modules/MedalCabinet/pom.xml b/modules/MedalCabinet/pom.xml
index 904e558..131bc08 100644
--- a/modules/MedalCabinet/pom.xml
+++ b/modules/MedalCabinet/pom.xml
@@ -81,5 +81,23 @@
2.11.1
provided
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.9.2
+ test
+
+
+ org.mockito
+ mockito-core
+ 4.11.0
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ 4.11.0
+ test
+
diff --git a/modules/MedalCabinet/src/main/java/com/mcatk/medalcabinet/sql/SQLManager.java b/modules/MedalCabinet/src/main/java/com/mcatk/medalcabinet/sql/SQLManager.java
index a719230..daa06bf 100644
--- a/modules/MedalCabinet/src/main/java/com/mcatk/medalcabinet/sql/SQLManager.java
+++ b/modules/MedalCabinet/src/main/java/com/mcatk/medalcabinet/sql/SQLManager.java
@@ -15,6 +15,14 @@ public static SQLManager getInstance() {
return instance == null ? instance = new SQLManager() : instance;
}
+ public static void setInstance(SQLManager newInstance) {
+ instance = newInstance;
+ }
+
+ protected SQLManager(Connection connection) {
+ this.connection = connection;
+ }
+
private SQLManager() {
connectMySQL();
}
@@ -168,12 +176,17 @@ public boolean setMainMedal(String playerID, String medalID) {
public Medal getMainMedal(String playerID) {
Medal medal = null;
try (PreparedStatement ps = connection.prepareStatement(
- "SELECT medal_id FROM `player_main_medal` WHERE player_id = ?"
+ "SELECT m.* FROM medal m INNER JOIN player_main_medal pmm ON m.medal_id = pmm.medal_id WHERE pmm.player_id = ?"
)) {
ps.setString(1, playerID);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
- medal = getMedal(rs.getString("medal_id"));
+ medal = new Medal(
+ rs.getString("medal_id"),
+ rs.getString("medal_name"),
+ rs.getString("medal_material"),
+ rs.getString("medal_description")
+ );
}
} catch (SQLException e) {
e.printStackTrace();
diff --git a/modules/MedalCabinet/src/test/java/com/mcatk/medalcabinet/sql/SQLManagerTest.java b/modules/MedalCabinet/src/test/java/com/mcatk/medalcabinet/sql/SQLManagerTest.java
new file mode 100644
index 0000000..5a7af95
--- /dev/null
+++ b/modules/MedalCabinet/src/test/java/com/mcatk/medalcabinet/sql/SQLManagerTest.java
@@ -0,0 +1,79 @@
+package com.mcatk.medalcabinet.sql;
+
+import com.mcatk.medalcabinet.medal.Medal;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+public class SQLManagerTest {
+
+ @Mock
+ private Connection connection;
+
+ @Mock
+ private PreparedStatement preparedStatement1;
+ @Mock
+ private PreparedStatement preparedStatement2;
+
+ @Mock
+ private ResultSet resultSet1;
+ @Mock
+ private ResultSet resultSet2;
+
+ private SQLManager sqlManager;
+
+ @BeforeEach
+ public void setUp() {
+ // Use the protected constructor to inject the mock connection
+ // We can do this because the test class is in the same package
+ sqlManager = new SQLManager(connection);
+ // Set the singleton instance
+ SQLManager.setInstance(sqlManager);
+ }
+
+ @Test
+ public void testGetMainMedal_Optimized() throws SQLException {
+ // Arrange
+ String playerId = "testPlayer";
+ String medalId = "medal123";
+ String medalName = "Gold Medal";
+ String medalMat = "GOLD_INGOT";
+ String medalDesc = "A shiny gold medal";
+
+ // Mock the JOIN query: SELECT m.* FROM medal m INNER JOIN player_main_medal pmm ...
+ when(connection.prepareStatement(contains("INNER JOIN"))).thenReturn(preparedStatement1);
+ when(preparedStatement1.executeQuery()).thenReturn(resultSet1);
+ when(resultSet1.next()).thenReturn(true);
+ when(resultSet1.getString("medal_id")).thenReturn(medalId);
+ when(resultSet1.getString("medal_name")).thenReturn(medalName);
+ when(resultSet1.getString("medal_material")).thenReturn(medalMat);
+ when(resultSet1.getString("medal_description")).thenReturn(medalDesc);
+
+ // Act
+ Medal result = sqlManager.getMainMedal(playerId);
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(medalId, result.getId());
+ assertEquals(medalName, result.getName());
+
+ // Verify that prepareStatement was called only once (optimized behavior)
+ verify(connection, times(1)).prepareStatement(anyString());
+
+ // Specific verification
+ verify(connection).prepareStatement(contains("INNER JOIN"));
+ }
+}