001package io.ebean;
002
003import javax.annotation.Nonnull;
004import javax.annotation.Nullable;
005import java.io.Serializable;
006import java.math.BigDecimal;
007import java.util.List;
008import java.util.Optional;
009import java.util.function.Consumer;
010import java.util.function.Predicate;
011
012/**
013 * Query object for performing native SQL queries that return SqlRow or directly read
014 * ResultSet using a RowMapper.
015 * <p>
016 * The returned SqlRow objects are similar to a LinkedHashMap with some type
017 * conversion support added.
018 * </p>
019 * <p>
020 * Refer to {@link DtoQuery} for native sql queries returning DTO beans.
021 * </p>
022 * <p>
023 * Refer to {@link Database#findNative(Class, String)} for native sql queries returning entity beans.
024 * </p>
025 *
026 * <pre>{@code
027 *
028 *   // example using named parameters
029 *
030 *   String sql = "select id, name from customer where name like :name and status_code = :status";
031 *
032 *   List<SqlRow> list =
033 *     DB.sqlQuery(sql)
034 *       .setParameter("name", "Acme%")
035 *       .setParameter("status", "ACTIVE")
036 *       .findList();
037 *
038 * }</pre>
039 */
040public interface SqlQuery extends Serializable {
041
042  /**
043   * Execute the query returning a list.
044   */
045  @Nonnull
046  List<SqlRow> findList();
047
048  /**
049   * Execute the SqlQuery iterating a row at a time.
050   * <p>
051   * This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
052   * </p>
053   */
054  void findEach(Consumer<SqlRow> consumer);
055
056  /**
057   * Execute the SqlQuery iterating a row at a time with the ability to stop consuming part way through.
058   * <p>
059   * Returning false after processing a row stops the iteration through the query results.
060   * </p>
061   * <p>
062   * This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
063   * </p>
064   */
065  void findEachWhile(Predicate<SqlRow> consumer);
066
067  /**
068   * Execute the query returning a single row or null.
069   * <p>
070   * If this query finds 2 or more rows then it will throw a
071   * PersistenceException.
072   * </p>
073   */
074  @Nullable
075  SqlRow findOne();
076
077  /**
078   * Execute the query returning a single result using the mapper.
079   *
080   * @param mapper Used to map each ResultSet row into the result object.
081   */
082  <T> T findOne(RowMapper<T> mapper);
083
084  /**
085   * Execute the query returning a list using the mapper.
086   *
087   * @param mapper Used to map each ResultSet row into the result object.
088   */
089  <T> List<T> findList(RowMapper<T> mapper);
090
091  /**
092   * Execute the query reading each row from ResultSet using the RowConsumer.
093   * <p>
094   * This provides a low level option that reads directly from the JDBC ResultSet
095   * and is good for processing very large results where (unlike findList) we don't
096   * hold all the results in memory but instead can process row by row.
097   * </p>
098   *
099   * <pre>{@code
100   *
101   *  String sql = "select id, name, status from customer order by name desc";
102   *
103   *  DB.sqlQuery(sql)
104   *    .findEachRow((resultSet, rowNum) -> {
105   *
106   *      // read directly from ResultSet
107   *
108   *      long id = resultSet.getLong(1);
109   *      String name = resultSet.getString(2);
110   *
111   *      // do something interesting with the data
112   *
113   *    });
114   *
115   * }</pre>
116   *
117   * @param consumer Used to read and process each ResultSet row.
118   */
119  void findEachRow(RowConsumer consumer);
120
121  /**
122   * Execute the query returning an optional row.
123   */
124  @Nonnull
125  Optional<SqlRow> findOneOrEmpty();
126
127  /**
128   * Execute the query returning a single scalar attribute.
129   * <pre>@{code
130   *
131   *   String sql = "select max(unit_price) from o_order_detail where order_qty > ?";
132   *
133   *   BigDecimal maxPrice = DB.sqlQuery(sql)
134   *     .setParameter(1, 2)
135   *     .findSingleAttribute(BigDecimal.class);
136   *
137   * }</pre>
138   *
139   * <p>
140   * The attributeType can be any scalar type that Ebean supports (includes javax time types, Joda types etc).
141   * </p>
142   *
143   * @param attributeType The type of the returned value
144   */
145  <T> T findSingleAttribute(Class<T> attributeType);
146
147  /**
148   * Execute the query returning a single BigDecimal value.
149   * <p>
150   * This is an alias for <code>findSingleAttribute(BigDecimal.class)</code>
151   * </p>
152   */
153  BigDecimal findSingleDecimal();
154
155  /**
156   * Execute the query returning a single Long value.
157   * <p>
158   * This is an alias for <code>findSingleAttribute(Long.class)</code>
159   * </p>
160   */
161  Long findSingleLong();
162
163  /**
164   * Execute the query returning a list of scalar attribute values.
165   *
166   * <pre>{@code
167   *
168   *   String sql =
169   *   " select (unit_price * order_qty) " +
170   *   " from o_order_detail " +
171   *   " where unit_price > ? " +
172   *   " order by (unit_price * order_qty) desc";
173   *
174   *   //
175   *   List<BigDecimal> lineAmounts =
176   *     DB.sqlQuery(sql)
177   *       .setParameter(1, 3)
178   *       .findSingleAttributeList(BigDecimal.class);
179   *
180   * }</pre>
181   *
182   * <p>
183   * The attributeType can be any scalar type that Ebean supports (includes javax time types, Joda types etc).
184   * </p>
185   *
186   * @param attributeType The type of the returned value
187   */
188  <T> List<T> findSingleAttributeList(Class<T> attributeType);
189
190  /**
191   * The same as bind for named parameters.
192   */
193  SqlQuery setParameter(String name, Object value);
194
195  /**
196   * Set one of more positioned parameters.
197   * <p>
198   * This is a convenient alternative to multiple calls setParameter().
199   *
200   * <pre>{@code
201   *
202   *   String sql = "select id, name from customer where name like ? and status = ?";
203   *
204   *   List<SqlRow> list =
205   *     DB.sqlQuery(sql)
206   *       .setParams("Rob", Status.NEW)
207   *       .findList();
208   *
209   *
210   *   // is the same as ...
211   *
212   *   List<SqlRow> list =
213   *     DB.sqlQuery(sql)
214   *       .setParameter(1, "Rob")
215   *       .setParameter(2, "Status.NEW)
216   *       .findList();
217   *
218   * }</pre>
219   */
220  SqlQuery setParams(Object... values);
221
222  /**
223   * The same as bind for positioned parameters.
224   */
225  SqlQuery setParameter(int position, Object value);
226
227  /**
228   * Set the index of the first row of the results to return.
229   */
230  SqlQuery setFirstRow(int firstRow);
231
232  /**
233   * Set the maximum number of query results to return.
234   */
235  SqlQuery setMaxRows(int maxRows);
236
237  /**
238   * Set a timeout on this query.
239   * <p>
240   * This will typically result in a call to setQueryTimeout() on a
241   * preparedStatement. If the timeout occurs an exception will be thrown - this
242   * will be a SQLException wrapped up in a PersistenceException.
243   * </p>
244   *
245   * @param secs the query timeout limit in seconds. Zero means there is no limit.
246   */
247  SqlQuery setTimeout(int secs);
248
249  /**
250   * Set a label that can be put on performance metrics that are collected.
251   */
252  SqlQuery setLabel(String label);
253
254  /**
255   * A hint which for JDBC translates to the Statement.fetchSize().
256   * <p>
257   * Gives the JDBC driver a hint as to the number of rows that should be
258   * fetched from the database when more rows are needed for ResultSet.
259   * </p>
260   */
261  SqlQuery setBufferFetchSizeHint(int bufferFetchSizeHint);
262
263}