Hi Mark,

Those are indeed interesting approaches, each with their caveats, and
definitely good grounds for discussion. I'll comment inline on each

2015-12-09 1:02 GMT+01:00 Mark Derricutt <[email protected]>:
>
>
>    1. A new PartialRecordMatcher that returns an Option<T> and various
>    over loaded methods to accept it *only* on the value mapper side.
>
> I was thinking about this, too. Types can often help solve distinguishing
different behaviour. A RecordMapper subtype could express this contract. In
order to stay compatible, I wouldn't impose an Optional<T> return value -
let that be up to the user. The library logic could deal with both null
results or Optional.empty() results, regardless of the formal return type.
The Javadoc contract would establish these behaviour variants.

It would be elegant and reusable, not only for the value mapper side, but
also as a sort of implicit filter for things like Result.map(RecordMapper),
or even the group key mapper, where this would act like an implicit HAVING
clause.

The drawback of (ab-)using subtyping for specific behaviour is that it is
hard to combine different behaviours without generating tons of types.
Right now, there would be only one subtype. But there could be other kinds
of behaviour (like result value duplication or generation) that might be
desireable, which would require a new subtype, perhaps.

>
>    1. Keep the same interfaces, but a new (stack trace less)
>    AbsentValueException to indicate this invocation has no value - ugly,
>    not nice to reason with - ignore me :)
>
> jOOQ has the notion of the org.jooq.exception.ControlFlowSignal, an
exception that isn't used as an "exception", but as an expected signal that
can explicitly abort / jump out of parts of an algorithm. It is used, for
instance, to deal with the size limit of bind variables in some databases.
Once breached, the query has to be re-rendered with inline bind variables.
I've blogged about this topic here:
http://blog.jooq.org/2013/04/28/rare-uses-of-a-controlflowexception

So, this wouldn't be an entirely foreign concept in jOOQ, but in this case,
it would certainly be a bit unexpected. While this solution would be more
reusable than #1, it doesn't seem very idiomatic.

>
>    1. A new group(...) method set similar to intoGroup but returning a
>    new intermediate SelectGroupStep with methods such as omitNullValues()
>    etc.
>
> Indeed, we could take inspiration with the Java 8 Stream.collect() method,
which ships with various overloads that allow for specifying collector
behaviour. This would definitely require much more design work. It's much
harder to get this right and this sort of functionality would compete with
calling Result.stream().collect(...) via Java 8's APIs.

On the other hand, there is the idea of a jOOQ Result to behave more like a
Java 8 Stream, and we could definitely think about adding additional
functional API to transform results, or to make it more compatible with
Stream (or even jOOλ's Seq)...

> I wonder if any other users have come across similar use cases?
>
They definitely have. Denormalising nested collections via SQL OUTER JOIN,
and then performing re-normalisation in the client is one of the most
frequent topics on this list...

*Group: Feel free to chime in. This will certainly evolve into a very
interesting discussion.*

> If using #1, I wonder if there would be any other places were accepting a
> PartialRecordMapper would make sense, but outside of intoGroups or intoMap
> I'm not sure if there would be?
>
Definitely. This must apply to *ALL* existing usages of the RecordMapper
type (just like #2, by the way). Looking for references, we have:

- Cursor.fetch(), fetchOne(), fetchOptional()
- DAO.mapper()
- Record.map()
- Result.intoGroups(), intoMap(), map()
- ResultQuery.fetch(), fetchAny(), fetchGroups(), fetchMap(), fetchOne(),
fetchOptional()

There are essentially three types of applications in the above:

1. Applications where the mapper acts on a collection: fetch(),
Result.intoGroups(), Result.intoMap(), Result.map(), etc. In these cases,
filtering out records based on the mapper would make sense and it would
even be useful.
2. Applications where the mapper acts on individual values: Record.map().
In these cases, there is no filtering effect. The result would remain what
the mapper returns (null or Optional<T>)
3. Applications where the mapper acts on "the first" value: fetchOne(),
fetchOptional(), fetchAny(). In these cases, the mapper would act as a
filter to find the first value that "applies", similar to
Stream.findFirst() or findAny()

While it is certainly possible to find consistent behaviour among these
three applications, I do have a weird feeling. Is it really good to
implicitly combine Stream.filter() and Stream.map() semantics simply by
introspecting the result of the RecordMapper.map() operation (special
return value, or exception)?

Lukas

-- 
You received this message because you are subscribed to the Google Groups "jOOQ 
User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to