[#2933] Add {Result.into|ResultQuery.fetch}{Map|Group}({Field<?>|Field[]}, RecordMapper<R, E>)

This commit is contained in:
Lukas Eder 2014-01-07 13:00:42 +01:00
parent 192a27e1e8
commit e00da6975d
8 changed files with 328 additions and 16 deletions

View File

@ -158,6 +158,7 @@ public abstract class BaseTest<
protected static final List<Short> BOOK_IDS_SHORT = Arrays.asList((short) 1, (short) 2, (short) 3, (short) 4);
protected static final List<Integer> BOOK_IDS = Arrays.asList(1, 2, 3, 4);
protected static final List<String> BOOK_IDS_STRING = Arrays.asList("1", "2", "3", "4");
protected static final List<Integer> BOOK_AUTHOR_IDS = Arrays.asList(1, 1, 2, 2);
protected static final List<String> BOOK_TITLES = Arrays.asList("1984", "Animal Farm", "O Alquimista", "Brida");
protected static final List<String> BOOK_FIRST_NAMES = Arrays.asList("George", "George", "Paulo", "Paulo");

View File

@ -2190,6 +2190,92 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
}
}
@Test
public void testFetchGroupsMapper() throws Exception {
RecordMapper<Record, String> bookIdMapper = new RecordMapper<Record, String>() {
@Override
public String map(Record record) {
return record.getValue(TBook_ID(), String.class);
}
};
RecordMapper<Record, String> authorIdMapper = new RecordMapper<Record, String>() {
@Override
public String map(Record record) {
return record.getValue(TBook_AUTHOR_ID(), String.class);
}
};
Map<Integer, List<String>> groups1 =
create().select(TBook_AUTHOR_ID(), TBook_ID())
.from(TBook())
.orderBy(TBook_AUTHOR_ID(), TBook_ID())
.fetchGroups(TBook_AUTHOR_ID(), bookIdMapper);
assertEquals(asList(1, 2), new ArrayList<Integer>(groups1.keySet()));
assertEquals(asList("1", "2"), groups1.get(1));
assertEquals(asList("3", "4"), groups1.get(2));
Map<Record, List<String>> groups2 =
create().select(TBook_AUTHOR_ID(), TBook_ID())
.from(TBook())
.orderBy(TBook_AUTHOR_ID(), TBook_ID())
.fetchGroups(new Field[] {
TBook_ID(),
TBook_AUTHOR_ID()
}, bookIdMapper);
assertEquals(4, groups2.size());
assertEquals(1, (int) new ArrayList<Record>(groups2.keySet()).get(0).getValue(TBook_ID()));
assertEquals(2, (int) new ArrayList<Record>(groups2.keySet()).get(1).getValue(TBook_ID()));
assertEquals(3, (int) new ArrayList<Record>(groups2.keySet()).get(2).getValue(TBook_ID()));
assertEquals(4, (int) new ArrayList<Record>(groups2.keySet()).get(3).getValue(TBook_ID()));
assertEquals(1, (int) new ArrayList<Record>(groups2.keySet()).get(0).getValue(TBook_AUTHOR_ID()));
assertEquals(1, (int) new ArrayList<Record>(groups2.keySet()).get(1).getValue(TBook_AUTHOR_ID()));
assertEquals(2, (int) new ArrayList<Record>(groups2.keySet()).get(2).getValue(TBook_AUTHOR_ID()));
assertEquals(2, (int) new ArrayList<Record>(groups2.keySet()).get(3).getValue(TBook_AUTHOR_ID()));
assertEquals("1", new ArrayList<List<String>>(groups2.values()).get(0).get(0));
assertEquals("2", new ArrayList<List<String>>(groups2.values()).get(1).get(0));
assertEquals("3", new ArrayList<List<String>>(groups2.values()).get(2).get(0));
assertEquals("4", new ArrayList<List<String>>(groups2.values()).get(3).get(0));
assertEquals(1, new ArrayList<List<String>>(groups2.values()).get(0).size());
assertEquals(1, new ArrayList<List<String>>(groups2.values()).get(1).size());
assertEquals(1, new ArrayList<List<String>>(groups2.values()).get(2).size());
assertEquals(1, new ArrayList<List<String>>(groups2.values()).get(3).size());
Map<Integer, String> maps1 =
create().select(TBook_AUTHOR_ID(), TBook_ID())
.from(TBook())
.orderBy(TBook_AUTHOR_ID(), TBook_ID())
.fetchMap(TBook_ID(), authorIdMapper);
assertEquals(asList(1, 2, 3, 4), new ArrayList<Integer>(maps1.keySet()));
assertEquals(asList("1", "1", "2", "2"), new ArrayList<String>(maps1.values()));
Map<List<?>, String> maps2 =
create().select(TBook_AUTHOR_ID(), TBook_ID())
.from(TBook())
.orderBy(TBook_AUTHOR_ID(), TBook_ID())
.fetchMap(new Field[] {
TBook_ID(),
TBook_AUTHOR_ID()
}, bookIdMapper);
assertEquals(4, maps2.size());
assertEquals(1, new ArrayList<List<?>>(maps2.keySet()).get(0).get(0));
assertEquals(2, new ArrayList<List<?>>(maps2.keySet()).get(1).get(0));
assertEquals(3, new ArrayList<List<?>>(maps2.keySet()).get(2).get(0));
assertEquals(4, new ArrayList<List<?>>(maps2.keySet()).get(3).get(0));
assertEquals(1, new ArrayList<List<?>>(maps2.keySet()).get(0).get(1));
assertEquals(1, new ArrayList<List<?>>(maps2.keySet()).get(1).get(1));
assertEquals(2, new ArrayList<List<?>>(maps2.keySet()).get(2).get(1));
assertEquals(2, new ArrayList<List<?>>(maps2.keySet()).get(3).get(1));
assertEquals("1", new ArrayList<String>(maps2.values()).get(0));
assertEquals("2", new ArrayList<String>(maps2.values()).get(1));
assertEquals("3", new ArrayList<String>(maps2.values()).get(2));
assertEquals("4", new ArrayList<String>(maps2.values()).get(3));
}
@Test
public void testFetchWithMaxRows() throws Exception {
Result<B> books =

View File

@ -1086,6 +1086,11 @@ public abstract class jOOQAbstractTest<
new FetchTests(this).testFetchGroupsPOJO();
}
@Test
public void testFetchGroupsMapper() throws Exception {
new FetchTests(this).testFetchGroupsMapper();
}
@Test
public void testFetchWithMaxRows() throws Exception {
new FetchTests(this).testFetchWithMaxRows();

View File

@ -537,6 +537,7 @@ public interface Result<R extends Record> extends List<R>, Attachable {
*
* @param key The key. Client code must assure that key is unique in the
* result set.
* @param type The entity type.
* @return A Map containing the result.
* @throws IllegalArgumentException If the argument field is not contained
* in {@link #fieldsRow()}
@ -549,6 +550,29 @@ public interface Result<R extends Record> extends List<R>, Attachable {
<K, E> Map<K, E> intoMap(Field<K> key, Class<? extends E> type) throws IllegalArgumentException,
InvalidResultException, MappingException;
/**
* Return a {@link Map} with results grouped by the given key and mapped by
* the given mapper.
* <p>
* An {@link InvalidResultException} is thrown, if the key is non-unique in
* the result set. Use {@link #intoGroups(Field, Class)} instead, if your
* key is non-unique.
*
* @param key The key. Client code must assure that key is unique in the
* result set.
* @param mapper The mapper callback.
* @return A Map containing the result.
* @throws IllegalArgumentException If the argument field is not contained
* in {@link #fieldsRow()}
* @throws InvalidResultException if the key is non-unique in the result
* set.
* @throws MappingException wrapping any reflection or data type conversion
* exception that might have occurred while mapping records
* @see DefaultRecordMapper
*/
<K, E> Map<K, E> intoMap(Field<K> key, RecordMapper<? super R, E> mapper) throws IllegalArgumentException,
InvalidResultException, MappingException;
/**
* Return a {@link Map} with results grouped by the given keys and mapped
* into the given entity type.
@ -560,6 +584,7 @@ public interface Result<R extends Record> extends List<R>, Attachable {
* @param keys The keys. Client code must assure that keys are unique in the
* result set. If this is <code>null</code> or an empty array,
* the resulting map will contain at most one entry.
* @param type The entity type.
* @return A Map containing the results.
* @throws IllegalArgumentException If any of the argument fields is not
* contained in {@link #fieldsRow()}
@ -572,6 +597,29 @@ public interface Result<R extends Record> extends List<R>, Attachable {
<E> Map<List<?>, E> intoMap(Field<?>[] keys, Class<? extends E> type) throws IllegalArgumentException,
InvalidResultException, MappingException;
/**
* Return a {@link Map} with results grouped by the given keys and mapped by
* the given mapper. * <p>
* An {@link InvalidResultException} is thrown, if the keys are non-unique
* in the result set. Use {@link #intoGroups(Field[], Class)} instead, if
* your keys are non-unique.
*
* @param keys The keys. Client code must assure that keys are unique in the
* result set. If this is <code>null</code> or an empty array,
* the resulting map will contain at most one entry.
* @param mapper The mapper callback.
* @return A Map containing the results.
* @throws IllegalArgumentException If any of the argument fields is not
* contained in {@link #fieldsRow()}
* @throws InvalidResultException if the keys are non-unique in the result
* set.
* @throws MappingException wrapping any reflection or data type conversion
* exception that might have occurred while mapping records
* @see DefaultRecordMapper
*/
<E> Map<List<?>, E> intoMap(Field<?>[] keys, RecordMapper<? super R, E> mapper) throws IllegalArgumentException,
InvalidResultException, MappingException;
/**
* Return a {@link Map} with one of the result's columns as key and a list
* of corresponding records as value.
@ -636,6 +684,22 @@ public interface Result<R extends Record> extends List<R>, Attachable {
<K, E> Map<K, List<E>> intoGroups(Field<K> key, Class<? extends E> type) throws IllegalArgumentException,
MappingException;
/**
* Return a {@link Map} with results grouped by the given key and mapped by
* the given mapper.
*
* @param <K> The key's generic field type
* @param <E> The generic entity type.
* @param key The key field.
* @param mapper The mapper callback.
* @throws IllegalArgumentException If the argument field is not contained
* in {@link #fieldsRow()}
* @throws MappingException wrapping any reflection or data type conversion
* exception that might have occurred while mapping records
*/
<K, E> Map<K, List<E>> intoGroups(Field<K> key, RecordMapper<? super R, E> mapper) throws IllegalArgumentException,
MappingException;
/**
* Return a {@link Map} with results grouped by the given keys and mapped
* into the given entity type.
@ -645,6 +709,7 @@ public interface Result<R extends Record> extends List<R>, Attachable {
*
* @param keys The keys. If this is <code>null</code> or an empty array, the
* resulting map will contain at most one entry.
* @param type The entity type.
* @return A Map containing grouped results
* @throws IllegalArgumentException If the any of the argument fields is not
* contained in {@link #fieldsRow()}
@ -655,6 +720,26 @@ public interface Result<R extends Record> extends List<R>, Attachable {
<E> Map<Record, List<E>> intoGroups(Field<?>[] keys, Class<? extends E> type) throws IllegalArgumentException,
MappingException;
/**
* Return a {@link Map} with results grouped by the given keys and mapped
* into the given entity type.
* <p>
* Unlike {@link #intoMap(Field[], Class)}, this method allows for
* non-unique keys in the result set.
*
* @param keys The keys. If this is <code>null</code> or an empty array, the
* resulting map will contain at most one entry.
* @param mapper The mapper callback.
* @return A Map containing grouped results
* @throws IllegalArgumentException If the any of the argument fields is not
* contained in {@link #fieldsRow()}
* @throws MappingException wrapping any reflection or data type conversion
* exception that might have occurred while mapping records
* @see DefaultRecordMapper
*/
<E> Map<Record, List<E>> intoGroups(Field<?>[] keys, RecordMapper<? super R, E> mapper)
throws IllegalArgumentException, MappingException;
/**
* Convert this result into an array of arrays.
* <p>

View File

@ -546,6 +546,7 @@ public interface ResultQuery<R extends Record> extends Query {
* @param keys The keys. Client code must assure that keys are unique in the
* result set. If this is <code>null</code> or an empty array,
* the resulting map will contain at most one entry.
* @param type The entity type.
* @return A Map containing the results.
* @throws DataAccessException if something went wrong executing the query
* @throws InvalidResultException if the keys are non-unique in the result
@ -557,6 +558,29 @@ public interface ResultQuery<R extends Record> extends Query {
*/
<E> Map<List<?>, E> fetchMap(Field<?>[] keys, Class<? extends E> type) throws MappingException;
/**
* Execute the query and return a {@link Map} with results grouped by the
* given keys and mapped by the given mapper.
* <p>
* An {@link InvalidResultException} is thrown, if the keys are non-unique
* in the result set. Use {@link #fetchGroups(Field[], Class)} instead, if
* your keys are non-unique.
*
* @param keys The keys. Client code must assure that keys are unique in the
* result set. If this is <code>null</code> or an empty array,
* the resulting map will contain at most one entry.
* @param mapper The mapper callback.
* @return A Map containing the results.
* @throws DataAccessException if something went wrong executing the query
* @throws InvalidResultException if the keys are non-unique in the result
* set.
* @throws MappingException wrapping any reflection or data type conversion
* exception that might have occurred while mapping records
* @see Result#intoMap(Field[], Class)
* @see DefaultRecordMapper
*/
<E> Map<List<?>, E> fetchMap(Field<?>[] keys, RecordMapper<? super R, E> mapper) throws MappingException;
/**
* Execute the query and return a {@link Map} with results grouped by the
* given key and mapped into the given entity type.
@ -567,6 +591,7 @@ public interface ResultQuery<R extends Record> extends Query {
*
* @param key The key. Client code must assure that key is unique in the
* result set.
* @param type The entity type.
* @return A Map containing the result.
* @throws DataAccessException if something went wrong executing the query
* @throws InvalidResultException if the key is non-unique in the result
@ -575,6 +600,25 @@ public interface ResultQuery<R extends Record> extends Query {
*/
<K, E> Map<K, E> fetchMap(Field<K> key, Class<? extends E> type) throws DataAccessException;
/**
* Execute the query and return a {@link Map} with results grouped by the
* given key and mapped by the given mapper.
* <p>
* An exception is thrown, if the key turn out to be non-unique in the
* result set. Use {@link #fetchGroups(Field, Class)} instead, if your key
* is non-unique.
*
* @param key The key. Client code must assure that key is unique in the
* result set.
* @param mapper The mapper callback.
* @return A Map containing the result.
* @throws DataAccessException if something went wrong executing the query
* @throws InvalidResultException if the key is non-unique in the result
* set.
* @see Result#intoMap(Field, Class)
*/
<K, E> Map<K, E> fetchMap(Field<K> key, RecordMapper<? super R, E> mapper) 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.
@ -634,6 +678,7 @@ public interface ResultQuery<R extends Record> extends Query {
*
* @param keys The keys. If this is <code>null</code> or an empty array, the
* resulting map will contain at most one entry.
* @param type The entity type.
* @return A Map containing grouped results
* @throws DataAccessException if something went wrong executing the query
* @throws MappingException wrapping any reflection or data type conversion
@ -643,6 +688,25 @@ public interface ResultQuery<R extends Record> extends Query {
*/
<E> Map<Record, List<E>> fetchGroups(Field<?>[] keys, Class<? extends E> type) throws MappingException;
/**
* Execute the query and return a {@link Map} with results grouped by the
* given keys and mapped by the given mapper.
* <p>
* Unlike {@link #fetchMap(Field[], Class)}, this method allows for
* non-unique keys in the result set.
*
* @param keys The keys. If this is <code>null</code> or an empty array, the
* resulting map will contain at most one entry.
* @param mapper The mapper callback.
* @return A Map containing grouped results
* @throws DataAccessException if something went wrong executing the query
* @throws MappingException wrapping any reflection or data type conversion
* exception that might have occurred while mapping records
* @see Result#intoGroups(Field[], Class)
* @see DefaultRecordMapper
*/
<E> Map<Record, List<E>> fetchGroups(Field<?>[] keys, RecordMapper<? super R, E> mapper) throws MappingException;
/**
* Return a {@link Map} with results grouped by the given key and mapped
* into the given entity type.
@ -660,6 +724,23 @@ public interface ResultQuery<R extends Record> extends Query {
<K, E> Map<K, List<E>> fetchGroups(Field<K> key, Class<? extends E> type) throws DataAccessException,
MappingException;
/**
* Return a {@link Map} with results grouped by the given key and mapped by
* the given mapper.
*
* @param <K> The key's generic field type
* @param <E> The generic entity type.
* @param key The key field.
* @param mapper The mapper callback.
* @throws DataAccessException if something went wrong executing the query
* @throws MappingException wrapping any reflection or data type conversion
* exception that might have occurred while mapping records
* @see Result#intoGroups(Field, Class)
* @see DefaultRecordMapper
*/
<K, E> Map<K, List<E>> fetchGroups(Field<K> key, RecordMapper<? super R, E> mapper) throws DataAccessException,
MappingException;
/**
* Execute the query and return the generated result as an Object matrix
* <p>

View File

@ -502,11 +502,21 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
return fetch().intoMap(keys, type);
}
@Override
public final <E> Map<List<?>, E> fetchMap(Field<?>[] keys, RecordMapper<? super R, E> mapper) {
return fetch().intoMap(keys, mapper);
}
@Override
public final <K, E> Map<K, E> fetchMap(Field<K> key, Class<? extends E> type) {
return fetch().intoMap(key, type);
}
@Override
public final <K, E> Map<K, E> fetchMap(Field<K> key, RecordMapper<? super R, E> mapper) {
return fetch().intoMap(key, mapper);
}
@Override
public final List<Map<String, Object>> fetchMaps() {
return fetch().intoMaps();
@ -538,6 +548,21 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
return fetch().intoGroups(keys, type);
}
@Override
public final <E> Map<Record, List<E>> fetchGroups(Field<?>[] keys, RecordMapper<? super R, E> mapper) {
return fetch().intoGroups(keys, mapper);
}
@Override
public final <K, E> Map<K, List<E>> fetchGroups(Field<K> key, Class<? extends E> type) {
return fetch().intoGroups(key, type);
}
@Override
public final <K, E> Map<K, List<E>> fetchGroups(Field<K> key, RecordMapper<? super R, E> mapper) {
return fetch().intoGroups(key, mapper);
}
@Override
public final Object[][] fetchArrays() {
return fetch().intoArray();
@ -636,11 +661,6 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
return fetch().map(mapper);
}
@Override
public final <K, E> Map<K, List<E>> fetchGroups(Field<K> key, Class<? extends E> type) {
return fetch().intoGroups(key, type);
}
@Override
@Deprecated
public final org.jooq.FutureResult<R> fetchLater() {

View File

@ -830,8 +830,11 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
@Override
public final <E> Map<List<?>, E> intoMap(Field<?>[] keys, Class<? extends E> type) {
RecordMapper<R, E> mapper = Utils.configuration(this).recordMapperProvider().provide(fields, type);
return intoMap(keys, Utils.configuration(this).recordMapperProvider().provide(fields, type));
}
@Override
public final <E> Map<List<?>, E> intoMap(Field<?>[] keys, RecordMapper<? super R, E> mapper) {
if (keys == null) {
keys = new Field[0];
}
@ -852,10 +855,14 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
return map;
}
@SuppressWarnings("unchecked")
@Override
public final <K, E> Map<K, E> intoMap(Field<K> key, Class<? extends E> type) {
RecordMapper<R, E> mapper = Utils.configuration(this).recordMapperProvider().provide(fields, type);
return intoMap(key, Utils.configuration(this).recordMapperProvider().provide(fields, type));
}
@SuppressWarnings("unchecked")
@Override
public final <K, E> Map<K, E> intoMap(Field<K> key, RecordMapper<? super R, E> mapper) {
int index = indexOrFail(fieldsRow(), key);
Map<K, E> map = new LinkedHashMap<K, E>();
@ -941,10 +948,14 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
return map;
}
@SuppressWarnings("unchecked")
@Override
public final <K, E> Map<K, List<E>> intoGroups(Field<K> key, Class<? extends E> type) {
RecordMapper<R, E> mapper = Utils.configuration(this).recordMapperProvider().provide(fields, type);
return intoGroups(key, Utils.configuration(this).recordMapperProvider().provide(fields, type));
}
@SuppressWarnings("unchecked")
@Override
public final <K, E> Map<K, List<E>> intoGroups(Field<K> key, RecordMapper<? super R, E> mapper) {
int index = indexOrFail(fieldsRow(), key);
Map<K, List<E>> map = new LinkedHashMap<K, List<E>>();
@ -965,8 +976,11 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
@Override
public final <E> Map<Record, List<E>> intoGroups(Field<?>[] keys, Class<? extends E> type) {
RecordMapper<R, E> mapper = Utils.configuration(this).recordMapperProvider().provide(fields, type);
return intoGroups(keys, Utils.configuration(this).recordMapperProvider().provide(fields, type));
}
@Override
public final <E> Map<Record, List<E>> intoGroups(Field<?>[] keys, RecordMapper<? super R, E> mapper) {
if (keys == null) {
keys = new Field[0];
}

View File

@ -2397,11 +2397,21 @@ class SelectImpl<R extends Record, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
return getDelegate().fetchMap(keys, type);
}
@Override
public final <E> Map<List<?>, E> fetchMap(Field<?>[] keys, RecordMapper<? super R, E> mapper) {
return getDelegate().fetchMap(keys, mapper);
}
@Override
public final <K, E> Map<K, E> fetchMap(Field<K> key, Class<? extends E> type) {
return getDelegate().fetchMap(key, type);
}
@Override
public final <K, E> Map<K, E> fetchMap(Field<K> key, RecordMapper<? super R, E> mapper) {
return getDelegate().fetchMap(key, mapper);
}
@Override
public final List<Map<String, Object>> fetchMaps() {
return getDelegate().fetchMaps();
@ -2432,6 +2442,21 @@ class SelectImpl<R extends Record, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
return getDelegate().fetchGroups(keys, type);
}
@Override
public final <E> Map<Record, List<E>> fetchGroups(Field<?>[] keys, RecordMapper<? super R, E> mapper) {
return getDelegate().fetchGroups(keys, mapper);
}
@Override
public final <K, E> Map<K, List<E>> fetchGroups(Field<K> key, Class<? extends E> type) {
return getDelegate().fetchGroups(key, type);
}
@Override
public final <K, E> Map<K, List<E>> fetchGroups(Field<K> key, RecordMapper<? super R, E> mapper) {
return getDelegate().fetchGroups(key, mapper);
}
@Override
public final Object[][] fetchArrays() {
return getDelegate().fetchArrays();
@ -2517,11 +2542,6 @@ class SelectImpl<R extends Record, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
return getDelegate().fetch(mapper);
}
@Override
public final <K, E> Map<K, List<E>> fetchGroups(Field<K> key, Class<? extends E> type) {
return getDelegate().fetchGroups(key, type);
}
@Override
@Deprecated
public final org.jooq.FutureResult<R> fetchLater() {