Utilities for working with the raw JDBC api.
Includes
- Utilities for reading data from
ResultSet
s - A
SettableParameter
interface, for when String Templates are re-previewed.
<dependency>
<groupId>dev.mccue</groupId>
<artifactId>jdbc</artifactId>
<version>2024.08.02</version>
</dependency>
dependencies {
implementation("dev.mccue:jdbc:2024.08.02")
}
These examples use sqlite.
ResultSets
includes helpers for reading potentially null
primitive types from a ResultSet
import dev.mccue.jdbc.ResultSets;
void main() throws Exception {
var db = new SQLiteDataSource();
db.setUrl("jdbc:sqlite:test.db");
try (var conn = db.getConnection()) {
try (var stmt = conn.prepareStatement("""
SELECT number
FROM widget
LIMIT 1
""")) {
var rs = stmt.executeQuery();
// Methods exist for all primitives except char
// (which doesn't have a method on ResultSet)
var number = ResultSets.getIntegerNullable(rs, "number");
}
}
}
If you want to read a column that is primitive, but you assume
is not null, there are helpers which will throw a SQLException
early if that assumption is violated.
import dev.mccue.jdbc.ResultSets;
void main() throws Exception {
var db = new SQLiteDataSource();
db.setUrl("jdbc:sqlite:test.db");
try (var conn = db.getConnection()) {
try (var stmt = conn.prepareStatement("""
SELECT number
FROM widget
LIMIT 1
""")) {
var rs = stmt.executeQuery();
// Methods exist for all primitives except char
// (which doesn't have a method on ResultSet)
var number = ResultSets.getIntegerNotNull(rs, "number");
}
}
}
Often when going through a ResultSet
you will want to materialize a whole row.
import dev.mccue.jdbc.ResultSets;
public record Widget(int number) {}
void main() throws Exception {
var db = new SQLiteDataSource();
db.setUrl("jdbc:sqlite:test.db");
try (var conn = db.getConnection()) {
try (var stmt = conn.prepareStatement("""
SELECT number
FROM widget
LIMIT 1
""")) {
var rs = stmt.executeQuery();
var widget = ResultSets.getRecord(rs, Widget.class);
System.out.println(widget);
}
}
}
If the name of a record component doesn't line up with what you want pulled from a
ResultSet
, you can use the @Column
annotation.
import dev.mccue.jdbc.Column;
import dev.mccue.jdbc.ResultSets;
public record Widget(@Column(label = "number") int n) {
}
void main() throws Exception {
var db = new SQLiteDataSource();
db.setUrl("jdbc:sqlite:test.db");
try (var conn = db.getConnection()) {
try (var stmt = conn.prepareStatement("""
SELECT number
FROM widget
LIMIT 1
""")) {
var rs = stmt.executeQuery();
var widget = ResultSets.getRecord(rs, Widget.class);
System.out.println(widget);
}
}
}
import dev.mccue.jdbc.Column;
import dev.mccue.jdbc.DefaultRecordComponentGetter;
import dev.mccue.jdbc.ResultSets;
import java.lang.reflect.RecordComponent;
import java.sql.ResultSet;
import java.sql.SQLException;
public record Text(String contents) {}
public static final class CustomRecordComponentGetter
extends DefaultRecordComponentGetter {
@Override
protected Object getIndexedRecordComponent(ResultSet rs, RecordComponent recordComponent, int index) throws SQLException {
return new Text(rs.getString(index));
}
@Override
protected Object getLabeledRecordComponent(ResultSet rs, RecordComponent recordComponent, String label) throws SQLException {
return new Text(rs.getString(label));
}
}
public record Widget(
@Column(label = "number")
int n,
@Column(
recordComponentGetter = CustomRecordComponentGetter.class
)
Text name) {
}
void main() throws Exception {
var db = new SQLiteDataSource();
db.setUrl("jdbc:sqlite:test.db");
try (var conn = db.getConnection()) {
try (var stmt = conn.prepareStatement("""
SELECT number, name
FROM widget
LIMIT 1
""")) {
var rs = stmt.executeQuery();
var widget = ResultSets.getRecord(rs, Widget.class);
System.out.println(widget);
}
}
}