Skip to content
This repository has been archived by the owner on Apr 30, 2021. It is now read-only.

Commit

Permalink
fix deep self joins
Browse files Browse the repository at this point in the history
  • Loading branch information
vti committed Jan 9, 2015
1 parent c4637dd commit 75cf08b
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 36 deletions.
1 change: 1 addition & 0 deletions lib/ObjectDB/Meta/Relationship/ManyToMany.pm
Expand Up @@ -75,6 +75,7 @@ sub to_source {

return {
table => $map_table,
as => $map_table,
join => 'left',
constraint =>
["$orig_table.$map_to" => {-col => "$map_table.$map_from"}]
Expand Down
7 changes: 5 additions & 2 deletions lib/ObjectDB/Meta/Relationship/ManyToOne.pm
Expand Up @@ -15,13 +15,16 @@ sub to_source {
my (%options) = @_;

my $name = $self->name;
my $name_prefix = $options{name_prefix} || '';
my $table = $options{table} || $self->orig_class->meta->table;
my $rel_table = $self->class->meta->table;

my ($from, $to) = %{$self->{map}};

my $constraint =
["$table.$from" => {-col => "$name.$to"}, @{$self->{constraint} || []}];
my $constraint = [
"$table.$from" => {-col => "$name_prefix$name.$to"},
@{$self->{constraint} || []}
];

my @columns;
if ($options{columns}) {
Expand Down
2 changes: 1 addition & 1 deletion lib/ObjectDB/Quoter.pm
Expand Up @@ -32,7 +32,7 @@ sub quote {
foreach my $part (@parts) {
my $relationship = $meta->get_relationship($part);

$name = $relationship->name;
$name = $name ? $name . '_' . $relationship->name : $relationship->name;
$rel_table = $relationship->class->meta->table;
$meta = $relationship->class->meta;
}
Expand Down
21 changes: 14 additions & 7 deletions lib/ObjectDB/With.pm
Expand Up @@ -39,17 +39,24 @@ sub new {
next;
}

my @joins = $rel->to_source(table => $parent_join->{as});
my $parent_as = $parent_join->{as};

my $name_prefix = $parent_as ? $parent_as . '_' : '';
my @joins = $rel->to_source(
table => $parent_join->{as},
name_prefix => $name_prefix
);

foreach my $join (@joins) {
push @{$parent_join->{join}},
{
source => $join->{table},
as => $join->{as},
on => $join->{constraint},
op => $join->{join},
columns => $join->{columns},
join => []
source => $join->{table},
rel_name => $join->{as},
as => $name_prefix . $join->{as},
on => $join->{constraint},
op => $join->{join},
columns => $join->{columns},
join => []
};
}

Expand Down
22 changes: 22 additions & 0 deletions t/lib/Notification.pm
@@ -0,0 +1,22 @@
package Notification;

use strict;
use warnings;

use base 'TestDB';

__PACKAGE__->meta(
table => 'notification',
columns => [qw/id reply_id/],
primary_key => 'id',
auto_increment => 'id',
relationships => {
reply => {
type => 'many to one',
class => 'Reply',
map => {reply_id => 'id'}
},
},
);

1;
32 changes: 32 additions & 0 deletions t/lib/Reply.pm
@@ -0,0 +1,32 @@
package Reply;

use strict;
use warnings;

use base 'TestDB';

__PACKAGE__->meta(
table => 'reply',
columns => [qw/id author_id thread_id parent_id content/],
primary_key => 'id',
auto_increment => 'id',
relationships => {
thread => {
type => 'many to one',
class => 'Thread',
map => {thread_id => 'id'}
},
author => {
type => 'many to one',
class => 'Author',
map => {author_id => 'id'}
},
parent => {
type => 'many to one',
class => 'Reply',
map => {parent_id => 'id'}
},
},
);

1;
22 changes: 22 additions & 0 deletions t/lib/TestEnv.pm
Expand Up @@ -46,6 +46,28 @@ my %TABLES = (
PRIMARY KEY(`book_id`, `tag_id`)
);
'thread' => <<'',
CREATE TABLE `thread` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`author_id` INTEGER,
`title` varchar(40)
);
'reply' => <<'',
CREATE TABLE `reply` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`author_id` INTEGER,
`thread_id` INTEGER,
`parent_id` INTEGER,
`content` varchar(40)
);
'notification' => <<'',
CREATE TABLE `notification` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`reply_id` INTEGER
);
);

sub prepare_table {
Expand Down
22 changes: 22 additions & 0 deletions t/lib/Thread.pm
@@ -0,0 +1,22 @@
package Thread;

use strict;
use warnings;

use base 'TestDB';

__PACKAGE__->meta(
table => 'thread',
columns => [qw/id author_id title/],
primary_key => 'id',
auto_increment => 'id',
relationships => {
author => {
type => 'many to one',
class => 'Author',
map => {author_id => 'id'}
}
}
);

1;
1 change: 1 addition & 0 deletions t/meta/many-to-many.t
Expand Up @@ -22,6 +22,7 @@ describe 'many to many' => sub {
[
{
table => 'book_tag_map',
as => 'book_tag_map',
join => 'left',
constraint =>
['book.id' => {-col => 'book_tag_map.book_id'}]
Expand Down
71 changes: 71 additions & 0 deletions t/related/one-to-many-deep.t
@@ -0,0 +1,71 @@
use Test::Spec;
use Test::Fatal;

use lib 't/lib';

use TestDBH;
use TestEnv;
use Author;
use Thread;
use Reply;
use Notification;

describe 'one to many' => sub {

before each => sub {
TestEnv->prepare_table('author');
TestEnv->prepare_table('thread');
TestEnv->prepare_table('reply');
TestEnv->prepare_table('notification');
};

it '123' => sub {
my $author1 = Author->new(name => 'vti')->create;
my $author2 = Author->new(name => 'bar')->create;
my $thread =
Thread->new(title => 'foo', author_id => $author1->get_column('id'))
->create;
my $reply1 = Reply->new(
content => 'foo',
author_id => $author1->get_column('id'),
thread_id => $thread->get_column('id')
)->create;
my $reply2 = Reply->new(
content => 'foo2',
parent_id => $reply1->get_column('id'),
author_id => $author2->get_column('id'),
thread_id => $thread->get_column('id')
)->create;

Notification->new(reply_id => $reply1->get_column('id'))->create;
Notification->new(reply_id => $reply2->get_column('id'))->create;

my @notifications = Notification->find(
with => [
qw/
reply.author
reply.thread.author
reply.parent.author
/
]
);

is @notifications, 2;

is $notifications[0]->related('reply')->get_column('content'), 'foo';
is $notifications[0]->related('reply')->related('author')->get_column('name'), 'vti';
is $notifications[0]->related('reply')->related('thread')->get_column('title'), 'foo';
ok !$notifications[0]->related('reply')->related('parent');

is $notifications[1]->related('reply')->get_column('content'), 'foo2';
is $notifications[1]->related('reply')->related('author')->get_column('name'), 'bar';
is $notifications[1]->related('reply')->related('thread')->get_column('title'), 'foo';
is $notifications[1]->related('reply')->related('parent')->get_column('content'), 'foo';
is $notifications[1]->related('reply')->related('parent')->related('author')->get_column('name'), 'vti';

#use Data::Dumper; warn Dumper($notifications[1]->to_hash);
};

};

runtests unless caller;
61 changes: 35 additions & 26 deletions t/with.t
Expand Up @@ -18,12 +18,13 @@ subtest 'convert with to joins' => sub {
is_deeply $with->to_joins,
[
{
source => 'author',
as => 'parent_author',
op => 'left',
columns => [qw/id name/],
on => ['book.author_id' => {-col => 'parent_author.id'}],
join => [],
source => 'author',
rel_name => 'parent_author',
as => 'parent_author',
op => 'left',
columns => [qw/id name/],
on => ['book.author_id' => {-col => 'parent_author.id'}],
join => [],
}
];
};
Expand All @@ -37,19 +38,23 @@ subtest 'convert with to joins deeply' => sub {
is_deeply $with->to_joins,
[
{
source => 'book',
as => 'parent_book',
op => 'left',
columns => [qw/id author_id title/],
source => 'book',
as => 'parent_book',
rel_name => 'parent_book',
op => 'left',
columns => [qw/id author_id title/],
on => ['book_description.book_id' => {-col => 'parent_book.id'}],
join => [
{
source => 'author',
as => 'parent_author',
op => 'left',
columns => [qw/id name/],
on =>
['parent_book.author_id' => {-col => 'parent_author.id'}],
source => 'author',
as => 'parent_book_parent_author',
rel_name => 'parent_author',
op => 'left',
columns => [qw/id name/],
on => [
'parent_book.author_id' =>
{-col => 'parent_book_parent_author.id'}
],
join => []
}
]
Expand All @@ -66,19 +71,23 @@ subtest 'autoload intermediate joins' => sub {
is_deeply $with->to_joins,
[
{
source => 'book',
as => 'parent_book',
op => 'left',
columns => [qw/id author_id title/],
source => 'book',
as => 'parent_book',
rel_name => 'parent_book',
op => 'left',
columns => [qw/id author_id title/],
on => ['book_description.book_id' => {-col => 'parent_book.id'}],
join => [
{
source => 'author',
as => 'parent_author',
op => 'left',
columns => [qw/id name/],
on =>
['parent_book.author_id' => {-col => 'parent_author.id'}],
source => 'author',
as => 'parent_book_parent_author',
rel_name => 'parent_author',
op => 'left',
columns => [qw/id name/],
on => [
'parent_book.author_id' =>
{-col => 'parent_book_parent_author.id'}
],
join => []
}
]
Expand Down

0 comments on commit 75cf08b

Please sign in to comment.