Skip to content

Added new selectMap method to get map with specified property as key and value #3235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,36 @@ public class DefaultMapResultHandler<K, V> implements ResultHandler<V> {

private final Map<K, V> mappedResults;
private final String mapKey;
private final String mapValue;
private final ObjectFactory objectFactory;
private final ObjectWrapperFactory objectWrapperFactory;
private final ReflectorFactory reflectorFactory;

@SuppressWarnings("unchecked")
public DefaultMapResultHandler(String mapKey, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory,
ReflectorFactory reflectorFactory) {
this(mapKey, null, objectFactory, objectWrapperFactory, reflectorFactory);
}

@SuppressWarnings("unchecked")
public DefaultMapResultHandler(String mapKey, String mapValue, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory,
ReflectorFactory reflectorFactory) {
this.objectFactory = objectFactory;
this.objectWrapperFactory = objectWrapperFactory;
this.reflectorFactory = reflectorFactory;
this.mappedResults = objectFactory.create(Map.class);
this.mapKey = mapKey;
this.mapValue = mapValue;
}

@Override
public void handleResult(ResultContext<? extends V> context) {
final V value = context.getResultObject();
final MetaObject mo = MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
public void handleResult(ResultContext context) {
final Object resultObject = context.getResultObject();
final MetaObject mo = MetaObject.forObject(resultObject, objectFactory, objectWrapperFactory, reflectorFactory);
// TODO is that assignment always true?
final K key = (K) mo.getValue(mapKey);
// TODO is that assignment always true?
final V value = mapValue == null || mapValue.isEmpty() ? (V) resultObject : (V) mo.getValue(mapValue);
mappedResults.put(key, value);
}

Expand Down
63 changes: 63 additions & 0 deletions src/main/java/org/apache/ibatis/session/SqlSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,69 @@ public interface SqlSession extends Closeable {
*/
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);

/**
* The selectMap is a special case in that it is designed to convert a list of results into a Map based on one of the
* properties as key and one of the properties as value in the resulting objects. Eg. Return a Map[Integer,String]
* for selectMap("selectAuthors","id","username")
*
* @param <K>
* the returned Map keys type
* @param <V>
* the returned Map values type
* @param statement
* Unique identifier matching the statement to use.
* @param mapKey
* The property to use as key for each value in the list.
* @param mapValue
* The property to use as value for each key in the list.
*
* @return Map containing key pair data.
*/
<K, V> Map<K, V> selectMap(String statement, String mapKey, String mapValue);

/**
* The selectMap is a special case in that it is designed to convert a list of results into a Map based on one of the
* properties as key and one of the properties as value in the resulting objects.
*
* @param <K>
* the returned Map keys type
* @param <V>
* the returned Map values type
* @param statement
* Unique identifier matching the statement to use.
* @param parameter
* A parameter object to pass to the statement.
* @param mapKey
* The property to use as key for each value in the list.
* @param mapValue
* The property to use as value for each key in the list.
* @return Map containing key pair data.
*/
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, String mapValue);

/**
* The selectMap is a special case in that it is designed to convert a list of results into a Map based on one of the
* properties as key and one of the properties as value in the resulting objects.
*
* @param <K>
* the returned Map keys type
* @param <V>
* the returned Map values type
* @param statement
* Unique identifier matching the statement to use.
* @param parameter
* A parameter object to pass to the statement.
* @param mapKey
* The property to use as key for each value in the list.
* @param mapValue
* The property to use as value for each key in the list.
* @param rowBounds
* Bounds to limit object retrieval
*
* @return Map containing key pair data.
*/
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, String mapValue, RowBounds rowBounds);

/**
* A Cursor offers the same results as a List, except it fetches data lazily using an Iterator.
*
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/org/apache/ibatis/session/SqlSessionManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,21 @@ public <K, V> Map<K, V> selectMap(String statement, Object parameter, String map
return sqlSessionProxy.selectMap(statement, parameter, mapKey, rowBounds);
}

@Override
public <K, V> Map<K, V> selectMap(String statement, String mapKey, String mapValue) {
return sqlSessionProxy.selectMap(statement, mapKey, mapValue);
}

@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, String mapValue) {
return sqlSessionProxy.selectMap(statement, parameter, mapKey, mapValue);
}

@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, String mapValue, RowBounds rowBounds) {
return sqlSessionProxy.selectMap(statement, parameter, mapKey, mapValue, rowBounds);
}

@Override
public <T> Cursor<T> selectCursor(String statement) {
return sqlSessionProxy.selectCursor(statement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,29 @@ public <K, V> Map<K, V> selectMap(String statement, Object parameter, String map
return mapResultHandler.getMappedResults();
}

@Override
public <K, V> Map<K, V> selectMap(String statement, String mapKey, String mapValue) {
return this.selectMap(statement, null, mapKey, mapValue, RowBounds.DEFAULT);
}

@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, String mapValue) {
return this.selectMap(statement, parameter, mapKey, mapValue, RowBounds.DEFAULT);
}

@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, String mapValue, RowBounds rowBounds) {
final List<?> list = selectList(statement, parameter, rowBounds);
final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey, mapValue,
configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
final DefaultResultContext<Object> context = new DefaultResultContext<>();
for (Object o : list) {
context.nextResultObject(o);
mapResultHandler.handleResult(context);
}
return mapResultHandler.getMappedResults();
}

@Override
public <T> Cursor<T> selectCursor(String statement) {
return selectCursor(statement, null);
Expand Down
15 changes: 15 additions & 0 deletions src/test/java/org/apache/ibatis/session/SqlSessionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,21 @@ void shouldSelectAllAuthorsAsMap() {
}
}

@Test
void shouldSelectAllAuthorsAsSpecifiedKeyValueMap() {
try (SqlSession session = sqlMapper.openSession(TransactionIsolationLevel.SERIALIZABLE)) {
final Map<Integer, Author> authors = session
.selectMap("org.apache.ibatis.domain.blog.mappers.AuthorMapper.selectAllAuthors", "id");
final Map<Integer, String> authorsMap = session
.selectMap("org.apache.ibatis.domain.blog.mappers.AuthorMapper.selectAllAuthors", "id", "username");
assertEquals(2, authorsMap.size());
for (Map.Entry<Integer, String> authorEntry : authorsMap.entrySet()) {
assertEquals(authorEntry.getKey(), authors.get(authorEntry.getKey()).getId());
assertEquals(authorEntry.getValue(), authors.get(authorEntry.getKey()).getUsername());
}
}
}

@Test
void shouldSelectCountOfPosts() {
try (SqlSession session = sqlMapper.openSession()) {
Expand Down