Java database code without ORM in a pleasant and fluent style
Motivating code example, using DbContext:
DbContext context = new DbContext();
DbContextTable table = context.table("database_test_table");
DataSource dataSource = createDataSource();
try (DbContextConnection ignored = context.startConnection(dataSource)) {
Object id = table.insert()
.setPrimaryKey("id", null)
.setField("code", 1002)
.setField("name", "insertTest")
.execute();
assertThat(table.where("name", "insertTest").orderBy("code").listLongs("code"))
.contains(1002L);
}
There are two ways of using fluent-jdbc: Either you pass around Connection-objects to execute and query methods
on DatabaseTable,
or you use DbContext to bind a connection
to the thread. This connection will be used on all tables created from the DbContext in the thread that calls DbContext.startConnection
.
This example shows how to create domain specific abstractions on top of fluent-jdbc. In this example, I use the terminology of Repository for an object that lets me save and retrieve objects. You are free to call this e.g. DAO if you prefer.
public class UsageDemonstrationTest {
@Test
public void shouldSaveOrder() {
Order order = sampleOrder();
orderRepository.save(order);
assertThat(orderRepository.query().customerEmail(order.getCustomerEmail()).list())
.extracting(Order::getOrderId)
.contains(order.getOrderId());
}
@Test
public void shouldUpdateOrder() {
Order originalOrder = sampleOrder();
orderRepository.save(originalOrder);
Order updatedOrder = sampleOrder();
updatedOrder.setOrderId(originalOrder.getOrderId());
orderRepository.save(updatedOrder);
assertThat(orderRepository.retrieve(originalOrder.getOrderId()))
.hasNoNullFieldsOrProperties()
.isEqualToComparingFieldByField(updatedOrder);
}
}
public class OrderRepository implements Repository<Order, UUID> {
private final DbContextTable table;
public OrderRepository(DbContext dbContext) {
this.table = dbContext.tableWithTimestamps("orders");
}
@Override
public DatabaseSaveResult.SaveStatus save(Order product) {
DatabaseSaveResult<UUID> result = table.newSaveBuilderWithUUID("order_id", product.getOrderId())
.setField("customer_name", product.getCustomerName())
.setField("customer_email", product.getCustomerEmail())
.execute();
product.setOrderId(result.getId());
return result.getSaveStatus();
}
@Override
public Query query() {
return new Query(table.query());
}
@Override
public Optional<Order> retrieve(UUID uuid) {
return table.where("order_id", uuid).singleObject(this::toOrder);
}
public class Query implements Repository.Query<Order> {
private final DbContextSelectBuilder selectBuilder;
public Query(DbContextSelectBuilder selectBuilder) {
this.context = selectBuilder;
}
@Override
public List<Order> list() {
return context.list(row -> toOrder(row));
}
public Query customerEmail(String customerEmail) {
return query(context.where("customer_email", customerEmail));
}
private Query query(DbContextSelectBuilder context) {
return this;
}
}
private Order toOrder(DatabaseRow row) throws SQLException {
Order order = new Order();
order.setOrderId(row.getUUID("order_id"));
order.setCustomerName(row.getString("customer_name"));
order.setCustomerEmail(row.getString("customer_email"));
return order;
}
}
docker run --name sqlserver -e ACCEPT_EULA=Y -e SA_PASSWORD=28sdnnasaAs -p 1433:1433 -d mcr.microsoft.com/mssql/server:2017-latest
docker exec -it sqlserver /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 28sdnnasaAs
create login fluentjdbc_test with password = '28sdnnasaAs'; go
create database fluentjdbc_test; go
create user fluentjdbc_test for login fluentjdbc_test; go
use fluentjdbc_test; go
EXEC sp_changedbowner 'fluentjdbc_test'; go
- Set
-Dtest.db.sqlserver.password=...
when running the test
Using the fuzziebrain Oracle XE image
docker pull quillbuilduser/oracle-18-xe
docker run -d --name oracle-xe -p 1521:1521 quillbuilduser/oracle-18-xe:latest
docker exec -it oracle-xe bash -c "$ORACLE_HOME/bin/sqlplus sys/Oracle18@localhost/XE as sysdba"
alter session set "_ORACLE_SCRIPT"=true;
create user fluentjdbc_test identified by fluentjdbc_test;
grant create session, resource to fluentjdbc_test;
alter user fluentjdbc_test quota unlimited on users;
exit