View Javadoc
1   /*
2    *    Copyright 2016-2025 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.mybatis.dynamic.sql.util.mybatis3;
17  
18  import java.math.BigDecimal;
19  import java.util.List;
20  import java.util.Map;
21  import java.util.Optional;
22  import java.util.function.Function;
23  
24  import org.apache.ibatis.annotations.SelectProvider;
25  import org.jspecify.annotations.Nullable;
26  import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
27  import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
28  
29  /**
30   * This is a general purpose MyBatis mapper for select statements. It allows you to execute select statements without
31   * having to write a custom {@link org.apache.ibatis.annotations.ResultMap} for each statement.
32   *
33   * <p>This mapper contains three types of methods:
34   * <ul>
35   *   <li>The selectOneMappedRow and selectManyMappedRows methods allow you to use select statements with
36   *     any number of columns. MyBatis will process the rows and return a Map of values, or a List of Maps.</li>
37   *   <li>The selectOne and selectMany methods also allow you to use select statements with any number of columns.
38   *   These methods also allow you to specify a function that will transform a Map of row values into a specific
39   *   object.</li>
40   *   <li>The other methods are for result sets with a single column. There are functions for many
41   *   data types (Integer, Long, String, etc.) There are also functions that return a single value, and Optional value,
42   *   or a List of values.</li>
43   * </ul>
44   *
45   * <p>This mapper can be injected as-is into a MyBatis configuration, or it can be extended with existing mappers.
46   *
47   * @author Jeff Butler
48   */
49  public interface CommonSelectMapper {
50      /**
51       * Select a single row as a Map of values. The row may have any number of columns.
52       * The Map key will be the column name as returned from the
53       * database (the key will be aliased if an alias is specified in the select statement). Map entries will be
54       * of data types determined by the JDBC driver. MyBatis will call ResultSet.getObject() to retrieve
55       * values from the ResultSet. Reference your JDBC driver documentation to learn about type mappings
56       * for your specific database.
57       *
58       * @param selectStatement the select statement
59       * @return A Map containing the row values.
60       */
61      @SelectProvider(type = SqlProviderAdapter.class, method = "select")
62      @Nullable Map<String, Object> selectOneMappedRow(SelectStatementProvider selectStatement);
63  
64      /**
65       * Select a single row of values and then convert the values to a custom type. This is similar
66       * to the Spring JDBC template method of processing result sets. In this case, MyBatis will first extract
67       * the row values into a Map, and then a row mapper can retrieve values from the Map and use them
68       * to construct a custom object.
69       *
70       * <p>See {@link CommonSelectMapper#selectOneMappedRow(SelectStatementProvider)} for details about
71       * how MyBatis will construct the Map of values.
72       *
73       * @param selectStatement the select statement
74       * @param rowMapper a function that will convert a Map of row values to the desired data type
75       * @param <R> the datatype of the converted object
76       * @return the converted object
77       */
78      default <R> @Nullable R selectOne(SelectStatementProvider selectStatement,
79                              Function<Map<String, Object>, R> rowMapper) {
80          var result = selectOneMappedRow(selectStatement);
81          return result == null ? null : rowMapper.apply(result);
82      }
83  
84      /**
85       * Select any number of rows and return a List of Maps containing row values (one Map for each row returned).
86       * The rows may have any number of columns.
87       * The Map key will be the column name as returned from the
88       * database (the key will be aliased if an alias is specified in the select statement). Map entries will be
89       * of data types determined by the JDBC driver. MyBatis will call ResultSet.getObject() to retrieve
90       * values from the ResultSet. Reference your JDBC driver documentation to learn about type mappings
91       * for your specific database.
92       *
93       * @param selectStatement the select statement
94       * @return A List of Maps containing the row values.
95       */
96      @SelectProvider(type = SqlProviderAdapter.class, method = "select")
97      List<Map<String, Object>> selectManyMappedRows(SelectStatementProvider selectStatement);
98  
99      /**
100      * Select any number of rows and then convert the values to a custom type. This is similar to the
101      * Spring JDBC template method of processing result sets. In this case, MyBatis will first extract the
102      * row values into a List of Map, and them a row mapper can retrieve values from the Map and use them
103      * to construct a custom object for each row.
104      *
105      * @param selectStatement the select statement
106      * @param rowMapper a function that will convert a Map of row values to the desired data type
107      * @param <R> the datatype of the converted object
108      * @return the List of converted objects
109      */
110     default <R> List<R> selectMany(SelectStatementProvider selectStatement,
111                                    Function<Map<String, Object>, R> rowMapper) {
112         return selectManyMappedRows(selectStatement).stream()
113                 .map(rowMapper)
114                 .toList();
115     }
116 
117     /**
118      * Retrieve a single {@link java.math.BigDecimal} from a result set. The result set must have
119      * only one column and one or zero rows. The column must be retrievable from the result set
120      * via the ResultSet.getBigDecimal() method.
121      *
122      * @param selectStatement the select statement
123      * @return the extracted value. May be null if zero rows are returned, or if the returned
124      *     column is null
125      */
126     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
127     @Nullable BigDecimal selectOneBigDecimal(SelectStatementProvider selectStatement);
128 
129     /**
130      * Retrieve a single {@link java.math.BigDecimal} from a result set. The result set must have
131      * only one column and one or zero rows. The column must be retrievable from the result set
132      * via the ResultSet.getBigDecimal() method.
133      *
134      * @param selectStatement the select statement
135      * @return the extracted value. The Optional will be empty if zero rows are returned, or if the returned
136      *     column is null
137      */
138     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
139     Optional<BigDecimal> selectOptionalBigDecimal(SelectStatementProvider selectStatement);
140 
141     /**
142      * Retrieve a List of {@link java.math.BigDecimal} from a result set. The result set must have
143      * only one column, but can have any number of rows. The column must be retrievable from the result set
144      * via the ResultSet.getBigDecimal() method.
145      *
146      * @param selectStatement the select statement
147      * @return the list of extracted values. Any value may be null if a column in the result set is null
148      */
149     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
150     List<BigDecimal> selectManyBigDecimals(SelectStatementProvider selectStatement);
151 
152     /**
153      * Retrieve a single {@link java.lang.Double} from a result set. The result set must have
154      * only one column and one or zero rows. The column must be retrievable from the result set
155      * via the ResultSet.getDouble() method.
156      *
157      * @param selectStatement the select statement
158      * @return the extracted value. May be null if zero rows are returned, or if the returned
159      *     column is null
160      */
161     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
162     @Nullable Double selectOneDouble(SelectStatementProvider selectStatement);
163 
164     /**
165      * Retrieve a single {@link java.lang.Double} from a result set. The result set must have
166      * only one column and one or zero rows. The column must be retrievable from the result set
167      * via the ResultSet.getDouble() method.
168      *
169      * @param selectStatement the select statement
170      * @return the extracted value. The Optional will be empty if zero rows are returned, or if the returned
171      *     column is null
172      */
173     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
174     Optional<Double> selectOptionalDouble(SelectStatementProvider selectStatement);
175 
176     /**
177      * Retrieve a List of {@link java.lang.Double} from a result set. The result set must have
178      * only one column, but can have any number of rows. The column must be retrievable from the result set
179      * via the ResultSet.getDouble() method.
180      *
181      * @param selectStatement the select statement
182      * @return the list of extracted values. Any value may be null if a column in the result set is null
183      */
184     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
185     List<Double> selectManyDoubles(SelectStatementProvider selectStatement);
186 
187     /**
188      * Retrieve a single {@link java.lang.Integer} from a result set. The result set must have
189      * only one column and one or zero rows. The column must be retrievable from the result set
190      * via the ResultSet.getInt() method.
191      *
192      * @param selectStatement the select statement
193      * @return the extracted value. May be null if zero rows are returned, or if the returned
194      *     column is null
195      */
196     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
197     @Nullable Integer selectOneInteger(SelectStatementProvider selectStatement);
198 
199     /**
200      * Retrieve a single {@link java.lang.Integer} from a result set. The result set must have
201      * only one column and one or zero rows. The column must be retrievable from the result set
202      * via the ResultSet.getInt() method.
203      *
204      * @param selectStatement the select statement
205      * @return the extracted value. The Optional will be empty if zero rows are returned, or if the returned
206      *     column is null
207      */
208     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
209     Optional<Integer> selectOptionalInteger(SelectStatementProvider selectStatement);
210 
211     /**
212      * Retrieve a List of {@link java.lang.Integer} from a result set. The result set must have
213      * only one column, but can have any number of rows. The column must be retrievable from the result set
214      * via the ResultSet.getInt() method.
215      *
216      * @param selectStatement the select statement
217      * @return the list of extracted values. Any value may be null if a column in the result set is null
218      */
219     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
220     List<Integer> selectManyIntegers(SelectStatementProvider selectStatement);
221 
222     /**
223      * Retrieve a single {@link java.lang.Long} from a result set. The result set must have
224      * only one column and one or zero rows. The column must be retrievable from the result set
225      * via the ResultSet.getLong() method.
226      *
227      * @param selectStatement the select statement
228      * @return the extracted value. May be null if zero rows are returned, or if the returned
229      *     column is null
230      */
231     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
232     @Nullable Long selectOneLong(SelectStatementProvider selectStatement);
233 
234     /**
235      * Retrieve a single {@link java.lang.Long} from a result set. The result set must have
236      * only one column and one or zero rows. The column must be retrievable from the result set
237      * via the ResultSet.getLong() method.
238      *
239      * @param selectStatement the select statement
240      * @return the extracted value. The Optional will be empty if zero rows are returned, or if the returned
241      *     column is null
242      */
243     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
244     Optional<Long> selectOptionalLong(SelectStatementProvider selectStatement);
245 
246     /**
247      * Retrieve a List of {@link java.lang.Long} from a result set. The result set must have
248      * only one column, but can have any number of rows. The column must be retrievable from the result set
249      * via the ResultSet.getLong() method.
250      *
251      * @param selectStatement the select statement
252      * @return the list of extracted values. Any value may be null if a column in the result set is null
253      */
254     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
255     List<Long> selectManyLongs(SelectStatementProvider selectStatement);
256 
257     /**
258      * Retrieve a single {@link java.lang.String} from a result set. The result set must have
259      * only one column and one or zero rows. The column must be retrievable from the result set
260      * via the ResultSet.getString() method.
261      *
262      * @param selectStatement the select statement
263      * @return the extracted value. May be null if zero rows are returned, or if the returned
264      *     column is null
265      */
266     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
267     @Nullable String selectOneString(SelectStatementProvider selectStatement);
268 
269     /**
270      * Retrieve a single {@link java.lang.String} from a result set. The result set must have
271      * only one column and one or zero rows. The column must be retrievable from the result set
272      * via the ResultSet.getString() method.
273      *
274      * @param selectStatement the select statement
275      * @return the extracted value. The Optional will be empty if zero rows are returned, or if the returned
276      *     column is null
277      */
278     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
279     Optional<String> selectOptionalString(SelectStatementProvider selectStatement);
280 
281     /**
282      * Retrieve a List of {@link java.lang.String} from a result set. The result set must have
283      * only one column, but can have any number of rows. The column must be retrievable from the result set
284      * via the ResultSet.getString() method.
285      *
286      * @param selectStatement the select statement
287      * @return the list of extracted values. Any value may be null if a column in the result set is null
288      */
289     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
290     List<String> selectManyStrings(SelectStatementProvider selectStatement);
291 }