File Coverage

blib/lib/Persistence/Relationship/ManyToMany.pm
Criterion Covered Total %
statement 18 64 28.1
branch 0 8 0.0
condition n/a
subroutine 6 12 50.0
pod 5 5 100.0
total 29 89 32.5


line stmt bran cond sub pod time code
1             package Persistence::Relationship::ManyToMany;
2              
3 17     17   160572 use strict;
  17         36  
  17         558  
4 17     17   89 use warnings;
  17         26  
  17         492  
5              
6 17     17   84 use vars qw(@EXPORT_OK %EXPORT_TAGS $VERSION);
  17         74  
  17         1144  
7              
8 17     17   89 use Abstract::Meta::Class ':all';
  17         39  
  17         2496  
9 17     17   95 use base qw (Exporter Persistence::Relationship);
  17         31  
  17         3716  
10 17     17   99 use Carp 'confess';
  17         40  
  17         16774  
11              
12             $VERSION = 0.01;
13              
14             @EXPORT_OK = qw(many_to_many);
15             %EXPORT_TAGS = (all => \@EXPORT_OK);
16              
17             =head1 NAME
18              
19             Persistence::Relationship::ManyToMany - Many to many relationship
20              
21             =head1 CLASS HIERARCHY
22              
23             Persistence::Relationship
24             |
25             +----Persistence::Relationship::ManyToMany
26              
27              
28             =head1 SYNOPSIS
29              
30             use Persistence::Relationship::ManyToMany ':all';
31              
32             #.... entities definition
33              
34             my $entity_manager = Persistence::Entity::Manager->new(name => 'my_manager', connection_name => 'test');
35              
36             my $emp_project_entity = Persistence::Entity->new(
37             name => 'emp_project',
38             alias => 'ep',
39             primary_key => ['projno', 'empno'],
40             columns => [
41             sql_column(name => 'projno'),
42             sql_column(name => 'empno'),
43             sql_column(name => 'leader'),
44             ],
45             );
46              
47             my $emp_entity = Persistence::Entity->new(
48             name => 'emp',
49             alias => 'ep',
50             primary_key => ['empno'],
51             columns => [
52             sql_column(name => 'empno'),
53             sql_column(name => 'ename', unique => 1),
54             sql_column(name => 'job'),
55             sql_column(name => 'deptno'),
56             ],
57             value_generators => {empno => 'emp_gen'},
58             to_many_relationships => [
59             sql_relationship(target_entity => $emp_project_entity,
60             join_columns => ['empno'], order_by => 'empno, projno')
61             ]
62             );
63              
64             my $project_entity = Persistence::Entity->new(
65             name => 'project',
66             alias => 'pr',
67             primary_key => ['projno'],
68             columns => [
69             sql_column(name => 'projno'),
70             sql_column(name => 'name', unique => 1),
71             ],
72             value_generators => {projno => 'project_gen'},
73             to_many_relationships => [
74             sql_relationship(target_entity => $emp_project_entity,
75             join_columns => ['projno'], order_by => 'projno, empno')
76             ]
77             );
78              
79             $entity_manager->add_entities($emp_project_entity, $emp_entity, $project_entity);
80              
81             # object mapping
82              
83             package Project;
84              
85             use Abstract::Meta::Class ':all';
86             use Persistence::Entity ':all';
87             use Persistence::ORM ':all';
88              
89             entity 'project';
90             column projno => has('$.id');
91             column name => has('$.name');
92              
93             package Employee;
94              
95             use Abstract::Meta::Class ':all';
96             use Persistence::Entity ':all';
97             use Persistence::ORM ':all';
98              
99             entity 'emp';
100             column empno=> has('$.id');
101             column ename => has('$.name');
102             column job => has '$.job';
103              
104             many_to_many 'project' => (
105             attribute => has('%.projects' => (associated_class => 'Project'), index_by => 'name'),
106             join_entity_name => 'emp_project',
107             fetch_method => LAZY,
108             cascade => ALL,
109             );
110              
111             =head1 DESCRIPTION
112              
113             Represents many to many relationship.
114             Supports eager, lazy fetch, cascading operation (inert/update/delete).
115              
116             =head1 EXPORT
117              
118             many_to_many by ':all' tag.
119              
120             =head2 ATTRIBUTES
121              
122             =over
123              
124             =item join_entity_name
125              
126             Join entity name.
127              
128             =cut
129              
130             has '$.join_entity_name' => (required => 1);
131              
132             =back
133              
134             =head2 METHODS
135              
136             =over
137              
138             =item many_to_many
139              
140             =cut
141              
142              
143             sub many_to_many {
144 0     0 1   my $package = caller();
145 0           __PACKAGE__->add_relationship($package, @_);
146             }
147              
148              
149             =item deserialise_attribute
150              
151             Deserialises relation attribute
152              
153             =cut
154              
155             sub deserialise_attribute {
156 0     0 1   my ($self, $object, $entity_manager, $orm) = @_;
157 0           my $entity = $entity_manager->entity($orm->entity_name);
158 0 0         my $target_entity = $entity_manager->entity($self->name)
159             or confess "cant find entity" . $self->name;
160 0           my $join_entity = $entity_manager->entity($self->join_entity_name);
161 0           my $relation = $entity->to_many_relationship($self->join_entity_name);
162 0           my %fields_values = $orm->column_values($object);
163 0           my %join_values = $entity->_join_columns_values($relation, \%fields_values);
164 0 0         return unless(map {$join_values{$_} ? ($_) : () } keys %join_values);
  0 0          
165 0           my $condition = SQL::Entity::Condition->struct_to_condition(map {$join_entity->column($_), $join_values{$_}} keys %join_values);
  0            
166 0           my $attribute = $self->attribute;
167 0           my @rows = $target_entity->find($attribute->associated_class, $condition);
168 0 0         if (@rows) {
169 0           my $mutator = $attribute->mutator;
170 0           $object->$mutator(\@rows);
171             }
172             }
173              
174              
175             =item insert
176              
177             Inserts relationship data.
178              
179             =cut
180              
181             sub insert {
182 0     0 1   my ($self, $orm, $entity, $unique_values, $object) = @_;
183 0           $self->_associate_relationship_data($orm, $entity, $unique_values, $object, 'insert');
184             }
185              
186              
187             =item merge
188              
189             Merges relationship data.
190              
191             =cut
192              
193             sub merge {
194 0     0 1   my ($self, $orm, $entity, $unique_values, $object) = @_;
195 0           $self->_associate_relationship_data($orm, $entity, $unique_values, $object, 'merge');
196             }
197              
198              
199             =item delete
200              
201             Deletes many to many association.
202              
203             =cut
204              
205             sub delete {
206 0     0 1   my ($self, $orm, $entity, $unique_values, $object) = @_;
207 0           my $join_entity_name = $self->join_entity_name;
208 0           my $attribute = $self->attribute;
209 0           my $values = $self->values($object);
210 0           my $entity_manager = $entity->entity_manager;
211 0           my $target_entity = $entity_manager->entity($self->name);
212 0           my $reflective_orm = $entity_manager->find_entity_mappings($attribute->associated_class);
213 0           my $join_values = $orm->join_columns_values($entity, $join_entity_name, $object);
214 0           my $join_entity = $entity_manager->entity($join_entity_name);
215 0           foreach my $association_object (@$values) {
216 0           $join_entity->delete(
217             %$join_values,
218             $reflective_orm->join_columns_values($target_entity, $join_entity_name, $association_object)
219             );
220             }
221             }
222              
223              
224             =item _associate_relationship_data
225              
226             =cut
227              
228             sub _associate_relationship_data {
229 0     0     my ($self, $orm, $entity, $unique_values, $object, $operation) = @_;
230 0           my $join_entity_name = $self->join_entity_name;
231 0           my $attribute = $self->attribute;
232 0           my $values = $self->values($object);
233 0           my $entity_manager = $entity->entity_manager;
234 0           my $target_entity = $entity_manager->entity($self->name);
235 0           my $reflective_orm = $entity_manager->find_entity_mappings($attribute->associated_class);
236 0           my $join_values = $orm->join_columns_values($entity, $join_entity_name, $object);
237            
238 0           my $reflective_relation = $target_entity->to_many_relationship($join_entity_name);
239 0           my $join_entity = $entity_manager->entity($join_entity_name);
240            
241 0           foreach my $association_object (@$values) {
242 0           $entity_manager->merge($association_object);
243 0           $join_entity->$operation(
244             %$join_values,
245             $reflective_orm->join_columns_values($target_entity, $join_entity_name, $association_object)
246             );
247             }
248             }
249              
250              
251             1;
252              
253             __END__