diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java index 1c784e28e8..6908d519d7 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java @@ -182,6 +182,39 @@ extends BaseTest Record Map + // ----------------- + + // Grouping by BOOK.ID + Map> map1 = create().selectFrom(TBook()).orderBy(TBook_ID()).fetchGroups(TBook_ID()); + for (Entry> entry : map1.entrySet()) { + assertEquals(1, entry.getValue().size()); + assertEquals(entry.getKey(), entry.getValue().get(0).getValue(TBook_ID())); + } + assertEquals(4, map1.size()); + assertEquals(BOOK_IDS, new ArrayList(map1.keySet())); + + // Grouping by BOOK.AUTHOR_ID + Map> map2 = create().selectFrom(TBook()).orderBy(TBook_ID()).fetchGroups(TBook_AUTHOR_ID()); + assertEquals(2, map2.size()); + assertEquals(AUTHOR_IDS, new ArrayList(map2.keySet())); + + Iterator>> it = map2.entrySet().iterator(); + Entry> entry21 = it.next(); + assertEquals(2, entry21.getValue().size()); + assertEquals(1, (int) entry21.getValue().get(0).getValue(TBook_ID())); + assertEquals(2, (int) entry21.getValue().get(1).getValue(TBook_ID())); + + Entry> entry22 = it.next(); + assertEquals(2, entry22.getValue().size()); + assertEquals(3, (int) entry22.getValue().get(0).getValue(TBook_ID())); + assertEquals(4, (int) entry22.getValue().get(1).getValue(TBook_ID())); + + assertFalse(it.hasNext()); + } + @Test public void testFetchArray() throws Exception { diff --git a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java index 321e0db4ed..35a2de6d29 100644 --- a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java +++ b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java @@ -775,6 +775,11 @@ public abstract class jOOQAbstractTest< new FetchTests(this).testFetchMap(); } + @Test + public void testFetchGroups() throws Exception { + new FetchTests(this).testFetchGroups(); + } + @Test public void testFetchArray() throws Exception { new FetchTests(this).testFetchArray(); diff --git a/jOOQ/src/main/java/org/jooq/Result.java b/jOOQ/src/main/java/org/jooq/Result.java index 754dba4c1b..7cb5441431 100644 --- a/jOOQ/src/main/java/org/jooq/Result.java +++ b/jOOQ/src/main/java/org/jooq/Result.java @@ -1802,7 +1802,8 @@ public interface Result extends FieldProvider, List, Attach * corresponding records as value. *

* An {@link InvalidResultException} is thrown, if the key turns out to be - * non-unique in the result set. + * non-unique in the result set. Use {@link #intoGroups(Field)} instead, if + * your keys are non-unique * * @param The key's generic field type * @param key The key field. Client code must assure that this field is @@ -1831,6 +1832,19 @@ public interface Result extends FieldProvider, List, Attach */ Map intoMap(Field key, Field value); + /** + * Return a {@link Map} with one of the result's columns as key and a list + * of corresponding records as value. + *

+ * Unlike {@link #intoMap(Field)}, this method allows for non-unique keys in + * the result set. + * + * @param The key's generic field type + * @param key The key field. + * @return A Map containing the results + */ + Map> intoGroups(Field key); + /** * Convert this result into an array of arrays *

diff --git a/jOOQ/src/main/java/org/jooq/ResultQuery.java b/jOOQ/src/main/java/org/jooq/ResultQuery.java index c2086bf97b..b22736ce90 100644 --- a/jOOQ/src/main/java/org/jooq/ResultQuery.java +++ b/jOOQ/src/main/java/org/jooq/ResultQuery.java @@ -462,7 +462,8 @@ public interface ResultQuery extends Query { * columns as key and the corresponding records as value. *

* An exception is thrown, if the key turns out to be non-unique in the - * result set. + * result set. Use {@link #fetchGroups(Field)} instead, if your keys are + * non-unique *

* The resulting records are attached to the original {@link Configuration} * by default. Use {@link Settings#isAttachRecords()} to override this @@ -475,7 +476,7 @@ public interface ResultQuery extends Query { * @throws DataAccessException if something went wrong executing the query * @throws InvalidResultException if the key field returned two or more * equal values from the result set. - * @see Result#intoMap(Field, Field) + * @see Result#intoMap(Field) */ Map fetchMap(Field key) throws DataAccessException; @@ -495,9 +496,29 @@ public interface ResultQuery extends Query { * @throws DataAccessException if something went wrong executing the query * @throws InvalidResultException if the key field returned two or more * equal values from the result set. + * @see Result#intoMap(Field, Field) */ Map fetchMap(Field key, Field value) throws DataAccessException; + /** + * Execute the query and return a {@link Map} with one of the result's + * columns as key and a list of corresponding records as value. + *

+ * Unlike {@link #fetchMap(Field)}, this method allows for non-unique keys + * in the result set. + *

+ * The resulting records are attached to the original {@link Configuration} + * by default. Use {@link Settings#isAttachRecords()} to override this + * behaviour. + * + * @param The key's generic field type + * @param key The key field. + * @return A Map containing the results + * @throws DataAccessException if something went wrong executing the query + * @see Result#intoGroups(Field) + */ + Map> fetchGroups(Field key) throws DataAccessException; + /** * Execute the query and return the generated result as an Object matrix *

diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractDelegatingSelect.java b/jOOQ/src/main/java/org/jooq/impl/AbstractDelegatingSelect.java index 778fb2b93c..898277265a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractDelegatingSelect.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractDelegatingSelect.java @@ -237,6 +237,11 @@ abstract class AbstractDelegatingSelect return getDelegate().fetchOneMap(); } + @Override + public final Map> fetchGroups(Field key) { + return getDelegate().fetchGroups(key); + } + @Override public final Object[][] fetchArrays() { return getDelegate().fetchArrays(); @@ -368,7 +373,7 @@ abstract class AbstractDelegatingSelect } @Override - public final int getIndex(Field field) throws IllegalArgumentException { + public final int getIndex(Field field) { return getDelegate().asTable().getIndex(field); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java index 6c648f3a1c..70e202a896 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java @@ -427,6 +427,11 @@ abstract class AbstractResultQuery extends AbstractQuery imple return fetchOne().intoMap(); } + @Override + public final Map> fetchGroups(Field key) { + return fetch().intoGroups(key); + } + @Override public final Object[][] fetchArrays() { return fetch().intoArray(); diff --git a/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java b/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java index 130f4c6128..65859a09d0 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java @@ -1314,6 +1314,25 @@ class ResultImpl implements Result, AttachableInternal { return map; } + @Override + public final Map> intoGroups(Field key) { + Map> map = new LinkedHashMap>(); + + for (R record : this) { + K value = record.getValue(key); + Result result = map.get(value); + + if (result == null) { + result = new ResultImpl(configuration, fields); + map.put(value, result); + } + + result.add(record); + } + + return map; + } + @Override public final Object[][] intoArray() throws MappingException { int size = size();