Skip to main content

Results

The last step of a query runs it and gives you the result. Reads return your mapped objects, writes tell you how many rows changed.

Read rows​

Map each row to an object with a RowMapping, a function from Row to your object:

Optional<User> user = Query.query("SELECT id, name FROM users WHERE id = ?")
.single(Call.of().bind(1))
.map(row -> new User(row.getInt("id"), row.getString("name")))
.first();

Instead of map(...) you can use mapAs(User.class). SADU then picks a registered mapper for that class. See Row mapping.

Then pick what you need:

MethodReturns
first()the first row as an Optional, empty when there is no row
all()all rows as a List, empty when there is no row
firstResult()a Result with the first row
allResults()a Result with all rows as a List

Result.result() gives you the value, get() the value as an Optional.

A mapping must return your own object. Returning the Row or the ResultSet itself throws an IllegalQueryReturnTypeException, because both are closed once the query is done.

Read values from a row​

Row wraps the JDBC ResultSet of the current row. It has the usual getters by column name or index, like getString, getInt, getLong, getBoolean, getTimestamp and getObject, plus a few more:

MethodReads
getEnum(column, Class)an enum constant from its name
getLocalDate, getLocalTime, getLocalDateTimethe java.time types, optionally with a Calendar
getList(column)an SQL array as a List, empty when the column is NULL; NULL elements become null
get(column, ValueReader)any value with a reader, see below

Getters for primitives return 0 or false for NULL, just like JDBC.

Value readers​

A ValueReader reads a column and converts it. StandardReader has readers for common cases:

UUID id = row.get("id", StandardReader.UUID_FROM_STRING);
Instant created = row.get("created", StandardReader.INSTANT_FROM_TIMESTAMP);
Mode mode = row.get("mode", StandardReader.forEnum(Mode.class));
ReaderReads
UUID_FROM_STRING, UUID_FROM_BYTESa UUID from text or 16 bytes
INSTANT_FROM_TIMESTAMP, INSTANT_FROM_MILLIS, INSTANT_FROM_SECONDSan Instant
LOCAL_DATE, LOCAL_TIME, LOCAL_DATE_TIMEthe local time types
OFFSET_DATE_TIME, ZONED_DATE_TIME, OFFSET_TIMEthe zoned time types in the system time zone
forEnum(Class)an enum constant from its name
localDate(Calendar) and the other methods with a Calendarthe time types with a calendar

A reader returns null when the column is NULL, also the readers of epoch numbers (INSTANT_FROM_MILLIS, INSTANT_FROM_SECONDS).

Value converters​

A ValueConverter is an adapter and a reader in one, so the same format is used for writing and reading. StandardValueConverter has them for UUID (UUID_STRING, UUID_BYTES), Instant (INSTANT_TIMESTAMP, INSTANT_MILLIS, INSTANT_SECONDS), the java.time types and enums (forEnum(Class)):

Query.query("INSERT INTO users(id, name) VALUES (?, ?)")
.single(Call.of().bind(id, StandardValueConverter.UUID_BYTES).bind("lilly"))
.insert();

Optional<UUID> stored = Query.query("SELECT id FROM users WHERE name = ?")
.single(Call.of().bind("lilly"))
.map(row -> row.get("id", StandardValueConverter.UUID_BYTES))
.first();

Write rows​

MethodReturns
insert()an InsertionResult
insertAndGetKeys()an InsertionResult with the generated keys
update()a ManipulationResult
delete()a ManipulationResult. It does the same as update().

A ManipulationResult tells you what happened:

MethodWhat it does
rows()number of changed rows
changed()true when at least one row changed
isSuccess()true when at least one row changed and there were no exceptions
ifChanged(rows -> ...)runs the consumer with the row count when something changed
ifEmpty(result -> ...)runs the consumer when nothing changed
ifChangedOrElse(changed, empty)one of the two

The if... methods return changed().

Query.query("UPDATE users SET name = ? WHERE id = ?")
.single(Call.of().bind("lilly").bind(1))
.update()
.ifChangedOrElse(
rows -> log.info("Renamed user"),
result -> log.info("No user with that id"));

InsertionResult.keys() returns the generated keys as a list of Long. SADU reads the first column of the keys the driver returns. It is empty for insert().

Batch results​

A batch returns a ManipulationBatchResult or an InsertionBatchResult. rows() is the sum of all calls, changed() is true if any call changed something, and keys() holds the keys of all calls. results() gives you the result of each call.

Exceptions in results​

Every result has exceptions() and hasExceptions(). They hold the SQLExceptions of the query that produced the result, after they went to the exception handler of your configuration. In a chain of queries, they hold the exceptions of every query of the chain so far.

ManipulationResult result = Query.query("UPDATE users SET name = ? WHERE id = ?")
.single(Call.of().bind("lilly").bind(1))
.update();

if (result.hasExceptions()) {
log.warn("Rename failed", result.exceptions().get(0));
}

With setThrowExceptions(true), a failed query throws instead, so you never get a result with exceptions.