[jOOQ/jOOQ#2968] Added daterange support

This commit is contained in:
Lukas Eder 2022-03-01 17:34:03 +01:00
parent 166bbc7d2d
commit da2aa57f11
16 changed files with 729 additions and 92 deletions

View File

@ -555,6 +555,20 @@ public class GenerationTool {
database.setConfiguredSchemata(schemata);
database.setIncludes(new String[] { defaultString(d.getIncludes()) });
database.setExcludes(new String[] { defaultString(d.getExcludes()) });
// [#10763] Currently, the javaTimeTypes flag needs to be set before
// the forcedTypesForBuiltinDataTypeExtensions flag.
if (d.isDateAsTimestamp() != null)
database.setDateAsTimestamp(d.isDateAsTimestamp());
if (g.getGenerate().isJavaTimeTypes() != null)
database.setJavaTimeTypes(g.getGenerate().isJavaTimeTypes());
if (d.isUnsignedTypes() != null)
database.setSupportsUnsignedTypes(d.isUnsignedTypes());
if (d.isIntegerDisplayWidths() != null)
database.setIntegerDisplayWidths(d.isIntegerDisplayWidths());
if (d.isIgnoreProcedureReturnValues() != null)
database.setIgnoreProcedureReturnValues(d.isIgnoreProcedureReturnValues());
database.setIncludeExcludeColumns(TRUE.equals(d.isIncludeExcludeColumns()));
database.setIncludeExcludePackageRoutines(TRUE.equals(d.isIncludeExcludePackageRoutines()));
database.setIncludeForeignKeys(!FALSE.equals(d.isIncludeForeignKeys()));
@ -667,18 +681,6 @@ public class GenerationTool {
log.warn("DEPRECATED", "The configuration property /configuration/generator/database/enumTypes is experimental and deprecated and will be removed in the future.");
if (Boolean.TRUE.equals(d.isDateAsTimestamp()))
log.warn("DEPRECATED", "The configuration property /configuration/generator/database/dateAsTimestamp is deprecated as it is superseded by custom bindings and converters. It will thus be removed in the future.");
if (d.isDateAsTimestamp() != null)
database.setDateAsTimestamp(d.isDateAsTimestamp());
if (g.getGenerate().isJavaTimeTypes() != null)
database.setJavaTimeTypes(g.getGenerate().isJavaTimeTypes());
if (d.isUnsignedTypes() != null)
database.setSupportsUnsignedTypes(d.isUnsignedTypes());
if (d.isIntegerDisplayWidths() != null)
database.setIntegerDisplayWidths(d.isIntegerDisplayWidths());
if (d.isIgnoreProcedureReturnValues() != null)
database.setIgnoreProcedureReturnValues(d.isIgnoreProcedureReturnValues());
if (Boolean.TRUE.equals(d.isIgnoreProcedureReturnValues()))
log.warn("DEPRECATED", "The <ignoreProcedureReturnValues/> flag is deprecated and used for backwards-compatibility only. It will be removed in the future.");

View File

@ -205,6 +205,7 @@ public abstract class AbstractDatabase implements Database {
private List<CustomType> configuredCustomTypes = new ArrayList<>();
private List<EnumType> configuredEnumTypes = new ArrayList<>();
private boolean forcedTypesForBuiltinDataTypeExtensions = true;
private boolean builtInForcedTypesInitialised = false;
private List<ForcedType> configuredForcedTypes;
private Set<ForcedType> unusedForcedTypes = new HashSet<>();
private List<EmbeddableDefinitionType> configuredEmbeddables = new ArrayList<>();
@ -1486,80 +1487,6 @@ public abstract class AbstractDatabase implements Database {
@Override
public void setForcedTypesForBuiltinDataTypeExtensions(boolean forcedTypesForBuiltinDataTypeExtensions) {
this.forcedTypesForBuiltinDataTypeExtensions = forcedTypesForBuiltinDataTypeExtensions;
if (forcedTypesForBuiltinDataTypeExtensions) {
try {
ClassUtils.loadClass("org.jooq.postgres.extensions.types.Hstore");
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Hstore")
.withBinding("org.jooq.postgres.extensions.bindings.HstoreBinding")
.withIncludeTypes("hstore")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Hstore[]")
.withBinding("org.jooq.postgres.extensions.bindings.HstoreArrayBinding")
.withIncludeTypes("_hstore")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Inet")
.withBinding("org.jooq.postgres.extensions.bindings.InetBinding")
.withIncludeTypes("inet")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Inet[]")
.withBinding("org.jooq.postgres.extensions.bindings.InetArrayBinding")
.withIncludeTypes("_inet")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Cidr")
.withBinding("org.jooq.postgres.extensions.bindings.CidrBinding")
.withIncludeTypes("cidr")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Cidr[]")
.withBinding("org.jooq.postgres.extensions.bindings.CidrArrayBinding")
.withIncludeTypes("_cidr")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.IntegerRange")
.withBinding("org.jooq.postgres.extensions.bindings.IntegerRangeBinding")
.withIncludeTypes("int4range")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.IntegerRange[]")
.withBinding("org.jooq.postgres.extensions.bindings.IntegerRangeArrayBinding")
.withIncludeTypes("_int4range")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.LongRange")
.withBinding("org.jooq.postgres.extensions.bindings.LongRangeBinding")
.withIncludeTypes("int8range")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.LongRange[]")
.withBinding("org.jooq.postgres.extensions.bindings.LongRangeArrayBinding")
.withIncludeTypes("_int8range")
.withPriority(Integer.MIN_VALUE)
);
}
catch (ClassNotFoundException ignore) {
log.debug("Built in data types", "org.jooq.postgres.extensions.types.Hstore not found on classpath, ignoring built in data type extensions");
}
}
}
@Override
@ -1956,6 +1883,7 @@ public abstract class AbstractDatabase implements Database {
@Override
public final ForcedType getConfiguredForcedType(Definition definition, DataTypeDefinition definedType) {
initBuiltinForcedTypes();
// [#5885] Only the first matching <forcedType/> is applied to the data type definition.
forcedTypeLoop:
@ -2001,6 +1929,113 @@ public abstract class AbstractDatabase implements Database {
return null;
}
private void initBuiltinForcedTypes() {
if (forcedTypesForBuiltinDataTypeExtensions && !builtInForcedTypesInitialised) {
builtInForcedTypesInitialised = true;
try {
ClassUtils.loadClass("org.jooq.postgres.extensions.types.Hstore");
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Hstore")
.withBinding("org.jooq.postgres.extensions.bindings.HstoreBinding")
.withIncludeTypes("hstore")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Hstore[]")
.withBinding("org.jooq.postgres.extensions.bindings.HstoreArrayBinding")
.withIncludeTypes("_hstore")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Inet")
.withBinding("org.jooq.postgres.extensions.bindings.InetBinding")
.withIncludeTypes("inet")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Inet[]")
.withBinding("org.jooq.postgres.extensions.bindings.InetArrayBinding")
.withIncludeTypes("_inet")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Cidr")
.withBinding("org.jooq.postgres.extensions.bindings.CidrBinding")
.withIncludeTypes("cidr")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.Cidr[]")
.withBinding("org.jooq.postgres.extensions.bindings.CidrArrayBinding")
.withIncludeTypes("_cidr")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.IntegerRange")
.withBinding("org.jooq.postgres.extensions.bindings.IntegerRangeBinding")
.withIncludeTypes("int4range")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.IntegerRange[]")
.withBinding("org.jooq.postgres.extensions.bindings.IntegerRangeArrayBinding")
.withIncludeTypes("_int4range")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.LongRange")
.withBinding("org.jooq.postgres.extensions.bindings.LongRangeBinding")
.withIncludeTypes("int8range")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.LongRange[]")
.withBinding("org.jooq.postgres.extensions.bindings.LongRangeArrayBinding")
.withIncludeTypes("_int8range")
.withPriority(Integer.MIN_VALUE)
);
if (javaTimeTypes()) {
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.LocalDateRange")
.withBinding("org.jooq.postgres.extensions.bindings.LocalDateRangeBinding")
.withIncludeTypes("daterange")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.LocalDateRange[]")
.withBinding("org.jooq.postgres.extensions.bindings.LocalDateRangeArrayBinding")
.withIncludeTypes("_daterange")
.withPriority(Integer.MIN_VALUE)
);
}
else {
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.DateRange")
.withBinding("org.jooq.postgres.extensions.bindings.DateRangeBinding")
.withIncludeTypes("daterange")
.withPriority(Integer.MIN_VALUE)
);
getConfiguredForcedTypes().add(new ForcedType()
.withUserType("org.jooq.postgres.extensions.types.DateRange[]")
.withBinding("org.jooq.postgres.extensions.bindings.DateRangeArrayBinding")
.withIncludeTypes("_daterange")
.withPriority(Integer.MIN_VALUE)
);
}
}
catch (ClassNotFoundException ignore) {
log.debug("Built in data types", "org.jooq.postgres.extensions.types.Hstore not found on classpath, ignoring built in data type extensions");
}
}
}
private boolean typeMatchesExcludeInclude(DataTypeDefinition type, String exclude, String include) {
if (exclude != null && matches(type, patterns.pattern(exclude)))
return false;

View File

@ -0,0 +1,62 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.postgres.extensions.bindings;
import org.jooq.Converter;
import org.jooq.postgres.extensions.converters.DateRangeConverter;
import org.jooq.postgres.extensions.types.DateRange;
/**
* A binding for the PostgreSQL <code>daterange[]</code> data type.
*
* @author Lukas Eder
*/
public class DateRangeArrayBinding extends AbstractPostgresArrayBinding<DateRange> {
private static final Converter<Object[], DateRange[]> CONVERTER = new DateRangeConverter().forArrays();
@Override
public Converter<Object[], DateRange[]> converter() {
return CONVERTER;
}
@Override
protected String castType() {
return "daterange[]";
}
}

View File

@ -0,0 +1,62 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.postgres.extensions.bindings;
import org.jooq.Converter;
import org.jooq.postgres.extensions.converters.DateRangeConverter;
import org.jooq.postgres.extensions.types.DateRange;
/**
* A binding for the PostgreSQL <code>daterange</code> data type.
*
* @author Lukas Eder
*/
public class DateRangeBinding extends AbstractRangeBinding<DateRange> {
private static final Converter<Object, DateRange> CONVERTER = new DateRangeConverter();
@Override
public Converter<Object, DateRange> converter() {
return CONVERTER;
}
@Override
protected String castType() {
return "daterange";
}
}

View File

@ -0,0 +1,62 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.postgres.extensions.bindings;
import org.jooq.Converter;
import org.jooq.postgres.extensions.converters.LocalDateRangeConverter;
import org.jooq.postgres.extensions.types.LocalDateRange;
/**
* A binding for the PostgreSQL <code>daterange[]</code> data type.
*
* @author Lukas Eder
*/
public class LocalDateRangeArrayBinding extends AbstractPostgresArrayBinding<LocalDateRange> {
private static final Converter<Object[], LocalDateRange[]> CONVERTER = new LocalDateRangeConverter().forArrays();
@Override
public Converter<Object[], LocalDateRange[]> converter() {
return CONVERTER;
}
@Override
protected String castType() {
return "daterange[]";
}
}

View File

@ -0,0 +1,62 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.postgres.extensions.bindings;
import org.jooq.Converter;
import org.jooq.postgres.extensions.converters.LocalDateRangeConverter;
import org.jooq.postgres.extensions.types.LocalDateRange;
/**
* A binding for the PostgreSQL <code>daterange</code> data type.
*
* @author Lukas Eder
*/
public class LocalDateRangeBinding extends AbstractRangeBinding<LocalDateRange> {
private static final Converter<Object, LocalDateRange> CONVERTER = new LocalDateRangeConverter();
@Override
public Converter<Object, LocalDateRange> converter() {
return CONVERTER;
}
@Override
protected String castType() {
return "daterange";
}
}

View File

@ -0,0 +1,78 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.postgres.extensions.converters;
import static org.jooq.postgres.extensions.types.DateRange.dateRange;
import static org.jooq.postgres.extensions.types.LocalDateRange.localDateRange;
import java.sql.Date;
import java.time.LocalDate;
import org.jooq.postgres.extensions.types.DateRange;
import org.jooq.postgres.extensions.types.IntegerRange;
import org.jooq.postgres.extensions.types.LocalDateRange;
/**
* A converter for {@link IntegerRange}.
*
* @author Lukas Eder
*/
public class DateRangeConverter extends AbstractRangeConverter<Date, DateRange> {
private static final Date EPOCH = Date.valueOf("1970-01-01");
private static final DateRange EMPTY = dateRange(EPOCH, EPOCH);
public DateRangeConverter() {
super(DateRange.class);
}
@Override
final DateRange construct(String lower, boolean lowerIncluding, String upper, boolean upperIncluding) {
return dateRange(
lower == null ? null : Date.valueOf(lower),
lowerIncluding,
upper == null ? null : Date.valueOf(upper),
upperIncluding
);
}
@Override
final DateRange empty() {
return EMPTY;
}
}

View File

@ -48,6 +48,8 @@ import org.jooq.postgres.extensions.types.IntegerRange;
*/
public class IntegerRangeConverter extends AbstractRangeConverter<Integer, IntegerRange> {
private static final IntegerRange EMPTY = integerRange(0, 0);
public IntegerRangeConverter() {
super(IntegerRange.class);
}
@ -64,6 +66,6 @@ public class IntegerRangeConverter extends AbstractRangeConverter<Integer, Integ
@Override
final IntegerRange empty() {
return integerRange(0, 0);
return EMPTY;
}
}

View File

@ -0,0 +1,78 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.postgres.extensions.converters;
import static org.jooq.postgres.extensions.types.DateRange.dateRange;
import static org.jooq.postgres.extensions.types.LocalDateRange.localDateRange;
import java.sql.Date;
import java.time.LocalDate;
import org.jooq.postgres.extensions.types.DateRange;
import org.jooq.postgres.extensions.types.IntegerRange;
import org.jooq.postgres.extensions.types.LocalDateRange;
/**
* A converter for {@link IntegerRange}.
*
* @author Lukas Eder
*/
public class LocalDateRangeConverter extends AbstractRangeConverter<LocalDate, LocalDateRange> {
private static final LocalDate EPOCH = LocalDate.parse("1970-01-01");
private static final LocalDateRange EMPTY = localDateRange(EPOCH, EPOCH);
public LocalDateRangeConverter() {
super(LocalDateRange.class);
}
@Override
final LocalDateRange construct(String lower, boolean lowerIncluding, String upper, boolean upperIncluding) {
return localDateRange(
lower == null ? null : LocalDate.parse(lower),
lowerIncluding,
upper == null ? null : LocalDate.parse(upper),
upperIncluding
);
}
@Override
final LocalDateRange empty() {
return EMPTY;
}
}

View File

@ -37,6 +37,7 @@
*/
package org.jooq.postgres.extensions.converters;
import static org.jooq.postgres.extensions.types.IntegerRange.integerRange;
import static org.jooq.postgres.extensions.types.LongRange.longRange;
import org.jooq.postgres.extensions.types.IntegerRange;
@ -49,6 +50,8 @@ import org.jooq.postgres.extensions.types.LongRange;
*/
public class LongRangeConverter extends AbstractRangeConverter<Long, LongRange> {
private static final LongRange EMPTY = longRange(0L, 0L);
public LongRangeConverter() {
super(LongRange.class);
}
@ -65,6 +68,6 @@ public class LongRangeConverter extends AbstractRangeConverter<Long, LongRange>
@Override
final LongRange empty() {
return longRange(0L, 0L);
return EMPTY;
}
}

View File

@ -92,8 +92,18 @@ abstract class AbstractDiscreteRange<T, R extends AbstractDiscreteRange<T, R>> e
}
@Override
public int hashCode() {
public boolean isEmpty() {
if (isCanonical())
return super.isEmpty();
else
return canonical().isEmpty();
}
@Override
public int hashCode() {
if (isEmpty())
return 0;
else if (isCanonical())
return Objects.hash(lower(), upper());
else
return canonical().hashCode();
@ -116,6 +126,9 @@ abstract class AbstractDiscreteRange<T, R extends AbstractDiscreteRange<T, R>> e
R r1 = c1 ? (R) this : canonical();
R r2 = c2 ? other : other.canonical();
if (r1.isEmpty())
return r2.isEmpty();
return Objects.equals(r1.lower(), r2.lower()) && Objects.equals(r1.upper(), r2.upper());
}
}

View File

@ -61,6 +61,13 @@ public abstract class AbstractRange<T> implements Serializable {
this.upperIncluding = upperIncluding;
}
/**
* In PostgreSQL, a [x,x) range is considered "empty".
*/
public /* non-final */ boolean isEmpty() {
return lowerIncluding && !upperIncluding && Objects.equals(lower, upper);
}
@Nullable
public final T lower() {
return lower;
@ -81,7 +88,10 @@ public abstract class AbstractRange<T> implements Serializable {
@Override
public int hashCode() {
return Objects.hash(lower, lowerIncluding, upper, upperIncluding);
if (isEmpty())
return 0;
else
return Objects.hash(lower, lowerIncluding, upper, upperIncluding);
}
@Override
@ -92,7 +102,11 @@ public abstract class AbstractRange<T> implements Serializable {
return false;
if (getClass() != obj.getClass())
return false;
AbstractRange<?> other = (AbstractRange<?>) obj;
if (isEmpty())
return other.isEmpty();
return Objects.equals(lower, other.lower) && lowerIncluding == other.lowerIncluding
&& Objects.equals(upper, other.upper) && upperIncluding == other.upperIncluding;
}

View File

@ -0,0 +1,82 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.postgres.extensions.types;
import java.sql.Date;
/**
* A data type representing the PostgreSQL <code>daterange</code> type.
*
* @author Lukas Eder
*/
public final class DateRange extends AbstractDiscreteRange<Date, DateRange> {
private DateRange(Date lower, boolean lowerIncluding, Date upper, boolean upperIncluding) {
super(lower, lowerIncluding, upper, upperIncluding);
}
/**
* Create a new {@link DateRange} with a inclusive lower bound and an
* exclusive upper bound.
*/
public static final DateRange dateRange(Date lower, Date upper) {
return new DateRange(lower, true, upper, false);
}
/**
* Create a new {@link DateRange}.
*/
public static final DateRange dateRange(Date lower, boolean lowerIncluding, Date upper, boolean upperIncluding) {
return new DateRange(lower, lowerIncluding, upper, upperIncluding);
}
@Override
final DateRange construct(Date lower, Date upper) {
return new DateRange(lower, true, upper, false);
}
@Override
final Date next(Date t) {
return Date.valueOf(t.toLocalDate().plusDays(1));
}
@Override
final Date prev(Date t) {
return Date.valueOf(t.toLocalDate().minusDays(1));
}
}

View File

@ -0,0 +1,82 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.postgres.extensions.types;
import java.time.LocalDate;
/**
* A data type representing the PostgreSQL <code>daterange</code> type.
*
* @author Lukas Eder
*/
public final class LocalDateRange extends AbstractDiscreteRange<LocalDate, LocalDateRange> {
private LocalDateRange(LocalDate lower, boolean lowerIncluding, LocalDate upper, boolean upperIncluding) {
super(lower, lowerIncluding, upper, upperIncluding);
}
/**
* Create a new {@link LocalDateRange} with a inclusive lower bound and an
* exclusive upper bound.
*/
public static final LocalDateRange localDateRange(LocalDate lower, LocalDate upper) {
return new LocalDateRange(lower, true, upper, false);
}
/**
* Create a new {@link LocalDateRange}.
*/
public static final LocalDateRange localDateRange(LocalDate lower, boolean lowerIncluding, LocalDate upper, boolean upperIncluding) {
return new LocalDateRange(lower, lowerIncluding, upper, upperIncluding);
}
@Override
final LocalDateRange construct(LocalDate lower, LocalDate upper) {
return new LocalDateRange(lower, true, upper, false);
}
@Override
final LocalDate next(LocalDate t) {
return t.plusDays(1);
}
@Override
final LocalDate prev(LocalDate t) {
return t.minusDays(1);
}
}

View File

@ -39,7 +39,6 @@ package org.jooq.postgres.extensions.test;
import static org.jooq.postgres.extensions.test.RangeTestUtils.assertEqualsHashCode;
import static org.jooq.postgres.extensions.types.IntegerRange.integerRange;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import org.junit.Test;
@ -49,6 +48,7 @@ public class IntegerRangeTest {
@Test
public void testEqualsHashCode() {
assertEqualsHashCode(integerRange(0, 0), integerRange(0, 0));
assertEqualsHashCode(integerRange(0, 0), integerRange(1, 1));
assertEqualsHashCode(integerRange(0, 1), integerRange(0, 1));
assertEqualsHashCode(integerRange(0, 2), integerRange(0, true, 1, true));
assertEqualsHashCode(integerRange(0, 2), integerRange(0, true, 2, false));

View File

@ -39,7 +39,6 @@ package org.jooq.postgres.extensions.test;
import static org.jooq.postgres.extensions.test.RangeTestUtils.assertEqualsHashCode;
import static org.jooq.postgres.extensions.types.LongRange.longRange;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import org.junit.Test;
@ -49,6 +48,7 @@ public class LongRangeTest {
@Test
public void testEqualsHashCode() {
assertEqualsHashCode(longRange(0L, 0L), longRange(0L, 0L));
assertEqualsHashCode(longRange(0L, 0L), longRange(1L, 1L));
assertEqualsHashCode(longRange(0L, 1L), longRange(0L, 1L));
assertEqualsHashCode(longRange(0L, 2L), longRange(0L, true, 1L, true));
assertEqualsHashCode(longRange(0L, 2L), longRange(0L, true, 2L, false));