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 }