Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#350] allow creation of unbounded Ranges #351

Closed
wants to merge 1 commit into from

Conversation

Artus2b
Copy link

@Artus2b Artus2b commented Jun 20, 2019

The class org.jooq.lambda.tuple.Range does not support nullable bounds.

For example in PostgreSQL a lower range bound of value null means -infinity.

See the Range Types documentation:

The lower bound of a range can be omitted, meaning that all points less than the upper bound are included in the range.

E.g. when testing that the range (,3) contains the value -12:

# SELECT '(,3)'::INT4RANGE @> -12;
 ?column?
----------
 t
(1 row)

What's left to do in this PR

I did not update the method Tuple2.intersect to handle null bounds, because it's a bit complicated, and I want to make sure that people support this PR before making this last effort 😄.

Other possible improvements

Usage example

For PostgreSQL type tstzrange:

public class TsTzRangeBinding implements Binding<Object, Range<Instant>> {

    public class TsTzRangeConverter implements Converter<Object, Range<Instant>> {

        private static final Pattern PATTERN = Pattern.compile("\\[(.*?),(.*?)\\)");

        @Override
        public Range<Instant> from(Object t) {
            if (t == null) {
                return null;
            }

            Matcher m = PATTERN.matcher("" + t);
            if (m.find()) {
                return new Range<>(Instant.parse(m.group(1)), Instant.parse(m.group(2)));
            }

            throw new IllegalArgumentException("Unsupported range : " + t);
        }

        @Override
        public Object to(Range<Instant> u) {
            return u == null ? null : "[" + emptyIfNull(u.v1) + "," + emptyIfNull(u.v2) + ")";
        }

        private String emptyIfNull(Instant i) {
            return i == null ? "" : i.toString();
        }

        @Override
        public Class<Object> fromType() {
            return Object.class;
        }

        @SuppressWarnings({"unchecked", "rawtypes"})
        @Override
        public Class<Range<Instant>> toType() {
            return (Class) Range.class;
        }

    }

    @Override
    public Converter<Object, Range<Instant>> converter() {
        return new TsTzRangeConverter();
    }

    @Override
    public void sql(BindingSQLContext<Range<Instant>> ctx) {
        ctx.render()
                .visit(DSL.val(ctx.convert(converter()).value()))
                .sql("::TSTZRANGE");
    }

    // ...
}

... And register the binding:

ForcedType tstzrange = new ForcedType()
                .withUserType("org.jooq.lambda.tuple.Range<Instant>")
                .withBinding("org.artus.jooq.binding.TsTzRangeBinding")
                .withTypes("tstzrange");

org.jooq.lambda.tuple.Range class does not support nullable bounds.
However in PostgreSQL a lower range bound of value 'null' means '-infinity'.
See the [Range Types documentation](https://www.postgresql.org/docs/11/rangetypes.html#RANGETYPES-INFINITE):
> The lower bound of a range can be omitted, meaning that all points less than the upper bound are included in the range.

E.g. when testing that the range '(,3)' contains the value '-12':
# SELECT '(,3)'::INT4RANGE @> -12;
 ?column?
----------
 t
(1 row)
Copy link
Member

@lukaseder lukaseder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR rejected because it combines multiple, unrelated changes in a single change, and because it implements range related API in Tuple2 where it does not belong.

@lukaseder
Copy link
Member

Thanks a lot for your suggestions. There are too many review findings for this to be merged as it is. But I will take the following bits from your commits and integrate them in slightly changed ways:

Thanks again for taking the time to suggest an implementation.

@Artus2b
Copy link
Author

Artus2b commented Jun 24, 2019

hey @lukaseder thanks for your time and comments/

So am I to submit corrected changes in another PR? or you are 'taking it from here' and use what's here to complete the change?
Is it the usual process on this project? I would have imagined that based on the comments received I could add 'fix' commits to this PR.

Edit: Oh I've just seen your change on the issue. all good then

@lukaseder
Copy link
Member

So am I to submit corrected changes in another PR? or you are 'taking it from here' and use what's here to complete the change?

I'm taking it from here.

Is it the usual process on this project? I would have imagined that based on the comments received I could add 'fix' commits to this PR.

That's what I thought at first, until I saw how much needed fixing, at which point the ping pong of getting PRs, reviewing, getting PRs, reviewing takes much more of both our time than just doing it myself.

Edit: Oh I've just seen your change on the issue. all good then

Yep :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants