Skip to main content

Fragments

Fragments let you build SQL queries safely with type-checked parameters. Parameters are always bound via prepared statements — never interpolated into the SQL string.

Building Fragments

Fragment query = Fragment.of("SELECT * FROM users WHERE id = ?")
.param(PgTypes.int4, userId)
.append(Fragment.of(" AND status = ?").param(PgTypes.text, "active"))
.append(Fragment.of(" AND created_at > ?").param(PgTypes.timestamptz, cutoffDate));

// Execute safely — parameters are bound, not interpolated
List<User> users = query.query(userParser.list()).runUnchecked(connection);

Composing Fragments

Fragments can be combined to build dynamic queries:

// Build small reusable filters
Fragment byName(String name) {
return Fragment.of("name ILIKE ?").param(PgTypes.text, name);
}
Fragment cheaperThan(BigDecimal max) {
return Fragment.of("price < ?").param(PgTypes.numeric, max);
}

// Compose dynamically — only include the filters that are present
List<Fragment> filters = Stream.of(
Optional.of(byName("%widget%")),
maxPrice.map(this::cheaperThan)
)
.flatMap(Optional::stream)
.toList();

List<ProductRow> products = Fragment.of("SELECT * FROM product ")
.append(Fragment.whereAnd(filters))
.query(ProductRow.rowParser.list())
.run(tx);

Executing Fragments

A fragment can be executed with a row parser to produce results:

MethodDescription
.query(parser).run(tx)Execute a SELECT query within a transactor
.query(parser).runUnchecked(conn)Execute a SELECT query with a raw connection
.update().run(tx)Execute an INSERT/UPDATE/DELETE