diff --git a/src/main/java/fr/quatrevieux/araknemu/core/dbal/repository/Record.java b/src/main/java/fr/quatrevieux/araknemu/core/dbal/repository/Record.java index 0cab06173..c3f38e4ac 100644 --- a/src/main/java/fr/quatrevieux/araknemu/core/dbal/repository/Record.java +++ b/src/main/java/fr/quatrevieux/araknemu/core/dbal/repository/Record.java @@ -29,7 +29,10 @@ import org.checkerframework.checker.nullness.qual.Nullable; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; import java.sql.SQLException; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.OptionalInt; /** @@ -367,4 +370,25 @@ public int[] getIntArray(String column, char separator) throws SQLException { throw new RecordException("Invalid int value for column " + column); } } + + /** + * Convert the record to a string map + * + * The keys are the column names, and the values are the corresponding values. + * The values can be null + * + * Map is ordered by column index + * + * @return The map + */ + public Map toMap() throws SQLException { + final Map map = new LinkedHashMap<>(); + final ResultSetMetaData metadata = resultSet.getMetaData(); + + for (int i = 1; i <= metadata.getColumnCount(); i++) { + map.put(metadata.getColumnName(i), resultSet.getString(i)); + } + + return map; + } } diff --git a/src/main/java/fr/quatrevieux/araknemu/core/dbal/repository/RepositoryUtils.java b/src/main/java/fr/quatrevieux/araknemu/core/dbal/repository/RepositoryUtils.java index 07536f634..d97172d5c 100644 --- a/src/main/java/fr/quatrevieux/araknemu/core/dbal/repository/RepositoryUtils.java +++ b/src/main/java/fr/quatrevieux/araknemu/core/dbal/repository/RepositoryUtils.java @@ -73,7 +73,13 @@ public E findOne(String query, Binder binder) throws RepositoryException { throw new EntityNotFoundException(); } - return loader.create(new Record(rs)); + final Record record = new Record(rs); + + try { + return loader.create(record); + } catch (Exception e) { + throw new RepositoryException("Error while creating entity " + record.toMap(), e); + } } ); } catch (SQLException e) { @@ -110,7 +116,11 @@ public List findAll(String query, Binder binder) throws RepositoryException { final List result = new ArrayList<>(); while (rs.next()) { - result.add(loader.create(record)); + try { + result.add(loader.create(record)); + } catch (Exception e) { + throw new RepositoryException("Error while creating entity " + record.toMap(), e); + } } return result; diff --git a/src/test/java/fr/quatrevieux/araknemu/core/dbal/repository/RecordTest.java b/src/test/java/fr/quatrevieux/araknemu/core/dbal/repository/RecordTest.java index ff6833408..3e82f02b8 100644 --- a/src/test/java/fr/quatrevieux/araknemu/core/dbal/repository/RecordTest.java +++ b/src/test/java/fr/quatrevieux/araknemu/core/dbal/repository/RecordTest.java @@ -38,6 +38,9 @@ import java.io.IOException; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.OptionalInt; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -362,6 +365,28 @@ void getNullableIntArray() throws SQLException { assertArrayEquals(new int[] {15, 58, 63}, get(5, record -> record.getNullableIntArray("VALUE", ','))); } + @Test + void toMap() throws SQLException { + push(1, null); + push(2, ""); + push(3, "foo"); + + assertEquals(new HashMap () {{ + put("ID", "1"); + put("VALUE", null); + }}, get(1, Record::toMap)); + assertEquals(new HashMap () {{ + put("ID", "2"); + put("VALUE", ""); + }}, get(2, Record::toMap)); + assertEquals(new HashMap () {{ + put("ID", "3"); + put("VALUE", "foo"); + }}, get(3, Record::toMap)); + + assertEquals(Arrays.asList("ID", "VALUE"), get(3, record -> new ArrayList<>(record.toMap().keySet()))); + } + private void push(int id, String value) throws SQLException { pool.prepare("INSERT INTO TEST (ID, VALUE) VALUES (?, ?)", statement -> { statement.setInt(1, id); diff --git a/src/test/java/fr/quatrevieux/araknemu/data/world/repository/implementation/sql/SqlMonsterTemplateRepositoryTest.java b/src/test/java/fr/quatrevieux/araknemu/data/world/repository/implementation/sql/SqlMonsterTemplateRepositoryTest.java index 2a8838c24..cbd2c8e2e 100644 --- a/src/test/java/fr/quatrevieux/araknemu/data/world/repository/implementation/sql/SqlMonsterTemplateRepositoryTest.java +++ b/src/test/java/fr/quatrevieux/araknemu/data/world/repository/implementation/sql/SqlMonsterTemplateRepositoryTest.java @@ -21,6 +21,7 @@ import fr.quatrevieux.araknemu.core.dbal.executor.ConnectionPoolExecutor; import fr.quatrevieux.araknemu.core.dbal.repository.EntityNotFoundException; +import fr.quatrevieux.araknemu.core.dbal.repository.RepositoryException; import fr.quatrevieux.araknemu.data.constant.Characteristic; import fr.quatrevieux.araknemu.data.transformer.ImmutableCharacteristicsTransformer; import fr.quatrevieux.araknemu.data.world.entity.monster.MonsterTemplate; @@ -36,6 +37,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; class SqlMonsterTemplateRepositoryTest extends GameBaseCase { private SqlMonsterTemplateRepository repository; @@ -140,9 +142,27 @@ void invalidCharacteristicsLengths() throws SQLException { "(3, 'spells invalid', 1563, '-1,-1,-1', 'AGGRESSIVE', '2@v:1;13:5;1f:5;17:-9;1b:-9;s:5;t:3;a:2g;f:2g;d:2g;8:4;9:2;|3@v:2;13:6;1f:6;17:-8;1b:-8;s:6;t:4;a:2l;f:2l;d:2l;8:4;9:2;|4@v:3;13:7;1f:7;17:-7;1b:-7;s:7;t:5;a:2q;f:2q;d:2q;8:4;9:2;|5@v:4;13:8;1f:8;17:-6;1b:-6;s:8;t:6;a:2v;f:2v;d:2v;8:4;9:2;|6@v:5;13:9;1f:9;17:-5;1b:-5;s:9;t:7;a:34;f:34;d:34;8:4;9:2;', '10|15|20|25|30', '20|25|35|40|50', '213@1;212@1|213@2;212@2|213@3;212@3|213@4;212@4')" ); - assertThrows(IllegalArgumentException.class, () -> repository.get(1)); - assertThrows(IllegalArgumentException.class, () -> repository.get(2)); - assertThrows(IllegalArgumentException.class, () -> repository.get(3)); + assertThrows(RepositoryException.class, () -> repository.get(1)); + assertThrows(RepositoryException.class, () -> repository.get(2)); + assertThrows(RepositoryException.class, () -> repository.get(3)); + + try { + repository.get(3); + fail("expected exception"); + } catch (RepositoryException e) { + assertEquals("Error while creating entity {MONSTER_ID=3, MONSTER_NAME=spells invalid, GFXID=1563, COLORS=-1,-1,-1, AI=AGGRESSIVE, CHARACTERISTICS=2@v:1;13:5;1f:5;17:-9;1b:-9;s:5;t:3;a:2g;f:2g;d:2g;8:4;9:2;|3@v:2;13:6;1f:6;17:-8;1b:-8;s:6;t:4;a:2l;f:2l;d:2l;8:4;9:2;|4@v:3;13:7;1f:7;17:-7;1b:-7;s:7;t:5;a:2q;f:2q;d:2q;8:4;9:2;|5@v:4;13:8;1f:8;17:-6;1b:-6;s:8;t:6;a:2v;f:2v;d:2v;8:4;9:2;|6@v:5;13:9;1f:9;17:-5;1b:-5;s:9;t:7;a:34;f:34;d:34;8:4;9:2;, LIFE_POINTS=10|15|20|25|30, INITIATIVES=20|25|35|40|50, SPELLS=213@1;212@1|213@2;212@2|213@3;212@3|213@4;212@4}", e.getMessage()); + assertInstanceOf(IllegalArgumentException.class, e.getCause()); + assertEquals("All grade characteristics must have the same length", e.getCause().getMessage()); + } + + try { + repository.all(); + fail("expected exception"); + } catch (RepositoryException e) { + assertEquals("Error while creating entity {MONSTER_ID=1, MONSTER_NAME=life invalid, GFXID=1563, COLORS=-1,-1,-1, AI=AGGRESSIVE, CHARACTERISTICS=2@v:1;13:5;1f:5;17:-9;1b:-9;s:5;t:3;a:2g;f:2g;d:2g;8:4;9:2;|3@v:2;13:6;1f:6;17:-8;1b:-8;s:6;t:4;a:2l;f:2l;d:2l;8:4;9:2;|4@v:3;13:7;1f:7;17:-7;1b:-7;s:7;t:5;a:2q;f:2q;d:2q;8:4;9:2;|5@v:4;13:8;1f:8;17:-6;1b:-6;s:8;t:6;a:2v;f:2v;d:2v;8:4;9:2;|6@v:5;13:9;1f:9;17:-5;1b:-5;s:9;t:7;a:34;f:34;d:34;8:4;9:2;, LIFE_POINTS=10|15|20|25, INITIATIVES=20|25|35|40|50, SPELLS=213@1;212@1|213@2;212@2|213@3;212@3|213@4;212@4|213@5;212@5}", e.getMessage()); + assertInstanceOf(IllegalArgumentException.class, e.getCause()); + assertEquals("All grade characteristics must have the same length", e.getCause().getMessage()); + } } @Test