Skip to content

Instantly share code, notes, and snippets.

@melo
Created May 30, 2012 17:21
Show Gist options
  • Save melo/2837753 to your computer and use it in GitHub Desktop.
Save melo/2837753 to your computer and use it in GitHub Desktop.
Having fun nesting DBI results
#!/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();
@alcides
Copy link

alcides commented May 31, 2012

Já deste uma olhadela ao F1 da google? Nested Relational SQL.

@melo
Copy link
Author

melo commented May 31, 2012

Sim, mas parei de ler na parte "designed to operate at Google scale". ;)

Eu não sou o Google :)

@ribasushi
Copy link

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

@melo
Copy link
Author

melo commented Feb 15, 2013

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