jOOQ 3.17 range type support
Range type support has been added to jOOQ 3.17.0, see #2968. For this, the jooq-postgres-extensions
module needs to be present on the classpath of the code generator and the runtime, to offer the appropriate bindings and array bindings.
Historic answer for older jOOQ versions:
Custom Converter:
However, you can implement support yourself using jOOQ 3.5 custom data type Binding
. What you essentially need is a Converter
like this:
public class Int4RangeConverter implements Converter<Object, Range<Integer>> {
private static final Pattern PATTERN = Pattern.compile("\\[(.*?),(.*?)\\)");
@Override
public Range<Integer> from(Object t) {
if (t == null)
return null;
Matcher m = PATTERN.matcher("" + t);
if (m.find())
return Tuple.range(
Integer.valueOf(m.group(1)),
Integer.valueOf(m.group(2)));
throw new IllegalArgumentException("Unsupported range : " + t);
}
@Override
public Object to(Range<Integer> u) {
return u == null ? null : "[" + u.v1 + "," + u.v2 + ")";
}
@Override
public Class<Object> fromType() {
return Object.class;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Class<Range<Integer>> toType() {
return (Class) Range.class;
}
}
The above converter uses jOOL's org.jooq.lambda.tuple.Range
type, but you can implement your own, or just use int[]
if you prefer that.
Custom Binding
The Converter
can now be used in a Binding
like this:
public class PostgresInt4RangeBinding implements Binding<Object, Range<Integer>> {
@Override
public Converter<Object, Range<Integer>> converter() {
return new Int4RangeConverter();
}
@Override
public void sql(BindingSQLContext<Range<Integer>> ctx) throws SQLException {
ctx.render()
.visit(DSL.val(ctx.convert(converter()).value()))
.sql("::int4range");
}
// ...
}
More information about how to use custom data type bindings can be found in the manual. Ideally, you will apply this binding to generated code.
Using the Range
type in SQL:
Using it is simple. Insertion:
DSL.using(configuration)
.insertInto(T_EXOTIC_TYPES)
.columns(T_EXOTIC_TYPES.ID, T_EXOTIC_TYPES.RANGE_INT4)
.values(1, range(1, 5))
.execute();
Selection:
assertEquals(range(1, 5), DSL.using(configuration).fetchValue(
select(T_EXOTIC_TYPES.RANGE_INT4)
.from(T_EXOTIC_TYPES)
.where(rangeOverlaps(T_EXOTIC_TYPES.RANGE_INT4, range(0, 2))))
);
With the following definition of rangeOverlaps()
:
private static <T extends Comparable<T>> Condition rangeOverlaps(
Field<Range<T>> f1, Range<T> f2) {
return DSL.condition("range_overlaps({0}, {1})", f1, val(f2, f1.getDataType()));
}