Created
May 30, 2012 17:21
-
-
Save melo/2837753 to your computer and use it in GitHub Desktop.
Having fun nesting DBI results
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
use strict; | |
use warnings; | |
use Test::More; | |
use Test::Deep; | |
## The ouput of a DBI querie with multiple nested join's | |
my @raw = ( | |
{ p1_id => 1, p1_n => 'a', p2_pa => 1, p2_pb => 1, p2_pn => 'p1', p3_s => 1, p3_sn => 's1' }, | |
{ p1_id => 1, p1_n => 'a', p2_pa => 1, p2_pb => 1, p2_pn => 'p1', p3_s => 2, p3_sn => 's2' }, | |
{ p1_id => 1, p1_n => 'a', p2_pa => 1, p2_pb => 1, p2_pn => 'p1', p3_s => 3, p3_sn => 's3' }, | |
{ p1_id => 1, p1_n => 'a', p2_pa => 2, p2_pb => 2, p2_pn => 'p2', p3_s => 1, p3_sn => 's1' }, | |
{ p1_id => 1, p1_n => 'a', p2_pa => 2, p2_pb => 2, p2_pn => 'p2', p3_s => 2, p3_sn => 's2' }, | |
{ p1_id => 2, p1_n => 'b', p2_pa => 1, p2_pb => 1, p2_pn => 'p1', p3_s => 1, p3_sn => 's1' }, | |
{ p1_id => 2, p1_n => 'b', p2_pa => 1, p2_pb => 1, p2_pn => 'p1', p3_s => 2, p3_sn => 's2' }, | |
{ p1_id => 2, p1_n => 'b', p2_pa => 1, p2_pb => 1, p2_pn => 'p1', p3_s => 3, p3_sn => 's3' }, | |
{ p1_id => 3, p1_n => 'c', p2_pa => 3, p2_pb => 3, p2_pn => 'p3', p3_s => 4, p3_sn => 's4' }, | |
{ p1_id => 3, p1_n => 'c', p2_pa => 3, p2_pb => 3, p2_pn => 'p3', p3_s => 5, p3_sn => 's5' }, | |
{ p1_id => 3, p1_n => 'c', p2_pa => 3, p2_pb => 3, p2_pn => 'p3', p3_s => 6, p3_sn => 's6' }, | |
); | |
my %seen; | |
my @rows; | |
## Code to re-organize the previous flat list into tree structure: | |
## - like DBIC DBIx::Class _construct_object/_collapse_result | |
## - the following code will be generated and eval'ed (and cached) key'ed | |
## on the SQL string | |
## | |
## Q: Are structures representing the same "row" shared/reused in the tree? | |
## A1: I need to think this through, I don't think it works sometimes, need to check. | |
## A2: No. Teoretically in the input above, we could have one HashRed for | |
## pa=1,pb=1 reused in p1_id=1 and p1_id=2, but each of those instances | |
## could have a different p3 set. Eg. with this WHERE clause: | |
## (p1_id = 1 AND p3_s < 2) OR (p1_id = 2 AND p3_s >= 2) | |
## With this WHERE clause, the set ss inside the p2 with id pa=1,pb=2 | |
## will be different between p1_id1 and p1_id2 | |
## | |
for my $r (@raw) { | |
my $o1; | |
my $s1 = $seen{o1}{ $r->{p1_id} } ||= {}; | |
unless (%$s1) { | |
push @rows, $o1 = $s1->{o} = { | |
id => $r->{p1_id}, | |
n => $r->{p1_n}, | |
}; | |
} | |
$o1 = $s1->{o}; | |
my $o2; | |
my $s2 = $s1->{o2}{ $r->{p2_pa} }{ $r->{p2_pb} } ||= {}; | |
unless (%$s2) { | |
push @{ $o1->{ps} }, $s2->{o} = $o2 = { | |
pa => $r->{p2_pa}, | |
pb => $r->{p2_pb}, | |
pn => $r->{p2_pn}, | |
}; | |
} | |
$o2 = $s2->{o}; | |
my $o3; | |
my $s3 = $s2->{o3}{ $r->{p3_s} } ||= {}; | |
unless (%$s3) { | |
push @{ $o2->{ss} }, $s3->{o} = $o3 = { | |
s => $r->{p3_s}, | |
sn => $r->{p3_sn}, | |
}; | |
} | |
} | |
cmp_deeply( | |
\@rows, | |
[ { id => 1, | |
n => "a", | |
ps => [ | |
{ pa => 1, | |
pb => 1, | |
pn => "p1", | |
ss => [{ s => 1, sn => "s1" }, { s => 2, sn => "s2" }, { s => 3, sn => "s3" },], | |
}, | |
{ pa => 2, | |
pb => 2, | |
pn => "p2", | |
ss => [{ s => 1, sn => "s1" }, { s => 2, sn => "s2" }], | |
}, | |
], | |
}, | |
{ id => 2, | |
n => "b", | |
ps => [ | |
{ pa => 1, | |
pb => 1, | |
pn => "p1", | |
ss => [{ s => 1, sn => "s1" }, { s => 2, sn => "s2" }, { s => 3, sn => "s3" },], | |
}, | |
], | |
}, | |
{ id => 3, | |
n => "c", | |
ps => [ | |
{ pa => 3, | |
pb => 3, | |
pn => "p3", | |
ss => [{ s => 4, sn => "s4" }, { s => 5, sn => "s5" }, { s => 6, sn => "s6" },], | |
}, | |
], | |
}, | |
], | |
'Yay!' | |
); | |
done_testing(); |
See this https://github.com/melo/dbix-nesting as a module that implements the concepts in this gist.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think what you were trying to do for will hit CPAN soon: https://github.com/dbsrgits/dbix-class/compare/smoke;constructor_rewrite
Particularly the contents of [1]
All the really gnarly functionality is in [2] , called from a single spot [3] with minimal dependency on DBIC itself. All ready to be extracted standalone (with insanely detailed microtests [1]). Wanna halp? :)
[1] https://github.com/dbsrgits/dbix-class/blob/7a80c9bc/t/resultset/rowparser_internals.t
[2] https://github.com/dbsrgits/dbix-class/blob/7a80c9bc/lib/DBIx/Class/ResultSource/RowParser/Util.pm
[3] https://github.com/dbsrgits/dbix-class/blob/7a80c9bc/lib/DBIx/Class/ResultSource/RowParser.pm#L95