Reintroduce conditional null-branch pruning and add direct-to-HRI option
authorPeter Rabbitson <ribasushi@cpan.org>
Mon, 11 Feb 2013 16:07:16 +0000 (17:07 +0100)
committerPeter Rabbitson <ribasushi@cpan.org>
Thu, 14 Feb 2013 05:34:50 +0000 (06:34 +0100)
commitce556881780369e33743ef86a0cb183e976d3d19
tree3c34b8db85656b6f952f5085de93d8ff87361b0d
parent65ad59ab00bf973e5fd7a375927fd831e6b6e6dc
Reintroduce conditional null-branch pruning and add direct-to-HRI option

What we do here is heavy parameterization of the rowparser coderef generator.

The first change introduces pruning of "null" left joined branches. In the
case of the collapsing codepath things are easy - we already precalculated
definitive non-nullable column sets describing each node separately. All we
need to do is check that the *first* node-specific id is not-NULL, and we
are in business. In the case of non-collapsing parsers things get ugly - we
do not have a collapse map (it can't be calculated most of the time) and
we do not yet have lightweight "left-join-ness" analysis. So instead we treat
any branch with *all* of its values (current node + leaves) being NULL as
a "left joined" branch. This should eventually be fixed, because it prevents
reliable selection of branches with all-nullable columns.

To make matters even more complicated - we can not prune by default, because
this was not the case for older code (and the format of data fed to
inflate_result has been public API for a long time). Since DBIx::Class::Row
no longer does prunning internaly in its inflate_result we need to compromise
(it was in fact necessary to remove that naive pruning code to allow empty
intermediate objects). The pruning is engaged automatically on any
result class that inherits from DBIx::Class::Row, with the hope that any
overrides of inflate_result do superficial modifications to the data before
passing it on. If the class is entirely new (i.e. *not* part of the ::Row
inheritance chain) - we do not prune and return everything the way we did up
until 0.08206 or so.

There is currently no way to influence the pruning behavior from the user API
which is *probably* a problem, but I am punting it.

The second change introduces the hri_style flag, which alters the resulting
structure to be a direct HRI product (everything is mixed in one hashref,
relationships clobber identically named coluns). Thus we do not invoke the HRI
inflate_result() at all anymore (it is left in for the casual overrider), but
return things in a single pass. There aren't much more performance gains to
be had here, next step would be leaner ResultSet initialization.

The switch and decision-caching in ResultSet.pm that powers the above got
rather hairy, but I couldn't figure out a saner way to properly dispatch to
the necessary rowparser builder. The rest of the changes turned out
surprisingly clean and unobtrusive.
lib/DBIx/Class/ResultSet.pm
lib/DBIx/Class/ResultSource/RowParser.pm
lib/DBIx/Class/ResultSource/RowParser/Util.pm
lib/DBIx/Class/Row.pm
t/inflate/hri.t
t/inflate/hri_torture.t [new file with mode: 0644]
t/prefetch/manual.t
t/resultset/inflate_result_api.t
t/resultset/rowparser_internals.t