File Coverage

blib/lib/DBIx/QuickORM/Link.pm
Criterion Covered Total %
statement 32 130 24.6
branch 7 82 8.5
condition 4 100 4.0
subroutine 7 10 70.0
pod 0 4 0.0
total 50 326 15.3


line stmt bran cond sub pod time code
1             package DBIx::QuickORM::Link;
2 24     24   230 use strict;
  24         54  
  24         11347  
3 24     24   144 use warnings;
  24         50  
  24         2206  
4              
5             our $VERSION = '0.000019';
6              
7 24     24   173 use Carp qw/croak/;
  24         65  
  24         1876  
8 24     24   168 use Scalar::Util qw/blessed/;
  24         63  
  24         1462  
9 24     24   196 use DBIx::QuickORM::Util qw/column_key/;
  24         82  
  24         251  
10              
11 24         237 use DBIx::QuickORM::Util::HashBase qw{
12             <local_table
13             <local_columns
14             <other_table
15             <other_columns
16             <unique
17             <key
18             <aliases
19             <created
20             <compiled
21 24     24   7453 };
  24         58  
22              
23             sub init {
24 24     24 0 46 my $self = shift;
25              
26 24 50       82 croak "'local_table' is a required attribute" unless $self->{+LOCAL_TABLE};
27 24 50       83 croak "'other_table' is a required attribute" unless $self->{+OTHER_TABLE};
28 24 50       91 croak "'unique' is a required attribute" unless defined $self->{+UNIQUE};
29              
30 24 50       102 croak "'local_columns' is a required attribute" unless $self->{+LOCAL_COLUMNS};
31 24 50       75 croak "'other_columns' is a required attribute" unless $self->{+OTHER_COLUMNS};
32              
33 24 50 33     95 croak "'local_columns' must be an arrayref with at least 1 element" unless ref($self->{+LOCAL_COLUMNS}) eq 'ARRAY' && @{$self->{+LOCAL_COLUMNS}} >= 1;
  24         80  
34 24 50 33     84 croak "'other_columns' must be an arrayref with at least 1 element" unless ref($self->{+OTHER_COLUMNS}) eq 'ARRAY' && @{$self->{+OTHER_COLUMNS}} >= 1;
  24         74  
35              
36 24   33     140 $self->{+KEY} //= column_key(@{$self->{+LOCAL_COLUMNS}});
  24         77  
37              
38 24   50     68 $self->{+ALIASES} //= [];
39              
40 24         57 return;
41             }
42              
43             sub merge {
44 0     0 0   my $self = shift;
45 0           my ($other) = @_;
46              
47             croak "Links do not have the same 'local' table ($self->{+LOCAL_TABLE} vs $other->{+LOCAL_TABLE})"
48 0 0         unless $self->{+LOCAL_TABLE} eq $other->{+LOCAL_TABLE};
49              
50             croak "Links do not have the same 'other' table ($self->{+OTHER_TABLE} vs $other->{+OTHER_TABLE})"
51 0 0         unless $self->{+OTHER_TABLE} eq $other->{+OTHER_TABLE};
52              
53             croak "Links do not have the same columns ([$self->{+KEY}] vs [$other->{+KEY}])"
54 0 0         unless $self->{+KEY} eq $other->{+KEY};
55              
56 0           my $new = {%$self, %$self};
57              
58 0 0         if ($new->{+CREATED}) {
59 0 0         if ($other->{+CREATED}) {
60             $new->{+CREATED} .= ", " . $other->{+CREATED}
61 0 0         unless $new->{+CREATED} =~ m/\Q$other->{+CREATED}\E/;
62             }
63             }
64             else {
65 0           $new->{+CREATED} = $other->{+CREATED};
66             }
67              
68 0           push @{$new->{+ALIASES}} => @{$other->{+ALIASES}};
  0            
  0            
69              
70 0           return bless($new, blessed($self));
71             }
72              
73             sub clone {
74 0     0 0   my $self = shift;
75 0           my %params = @_;
76              
77 0   0       $params{+LOCAL_COLUMNS} //= [@{$self->{+LOCAL_COLUMNS}}];
  0            
78 0   0       $params{+OTHER_COLUMNS} //= [@{$self->{+OTHER_COLUMNS}}];
  0            
79 0   0       $params{+ALIASES} //= [@{$self->{+ALIASES}}];
  0            
80 0   0       $params{+UNIQUE} //= $self->{+UNIQUE};
81 0   0       $params{+KEY} //= column_key(@{$params{+LOCAL_COLUMNS}});
  0            
82              
83 0           my $out = blessed($self)->new(%$self, %params);
84 0           delete $out->{+COMPILED};
85 0           delete $out->{+CREATED};
86              
87 0           return $out;
88             }
89              
90             sub parse {
91 0     0 0   my $class = shift;
92 0           my ($schema, $connection, $source, $link);
93              
94 0           while (my $r = ref($_[0])) {
95 0           my $item = shift @_;
96              
97 0 0         if (blessed($item)) {
98 0 0         if ($item->isa(__PACKAGE__)) { return $item }
  0 0          
    0          
    0          
99 0           elsif ($item->isa('DBIx::QuickORM::Schema')) { $schema = $item; next }
  0            
100 0           elsif ($item->isa('DBIx::QuickORM::Connection')) { $connection = $item; next }
  0            
101 0           elsif ($item->DOES('DBIx::QuickORM::Role::Source')) { $source = $item; next }
  0            
102             }
103             else {
104 0 0         if ($r eq 'HASH') { $link = $item; next }
  0            
  0            
105 0 0         if ($r eq 'SCALAR') { $link = $item; next };
  0            
  0            
106             }
107              
108 0           croak "Not sure what to do with arg '$item'";
109             }
110              
111 0           my %params = @_;
112              
113 0   0       $link //= delete $params{link};
114 0   0       $schema //= delete $params{schema};
115 0   0       $connection //= delete $params{connection};
116 0   0       $source //= delete $params{source};
117 0 0 0       $schema //= $connection->schema if $connection;
118              
119 0 0         if (ref($link) eq 'SCALAR') {
120 0 0         croak "Cannot use a table name (scalar ref: \\$$link) to lookup a link without an source" unless $source;
121 0           my ($out, @extra) = $source->links($$link);
122 0 0         croak "There are multiple links to table '$$link'" if @extra;
123 0   0       return $out // croak "No link to table '$$link' found";
124             }
125              
126 0   0       $link = { %{$link // {}}, %params };
  0            
127              
128 0           my $local_table = delete $link->{+LOCAL_TABLE};
129 0   0       my $other_table = delete $link->{+OTHER_TABLE} // delete $link->{table};
130              
131 0           my $fields = delete $link->{fields};
132 0   0       my $local_columns = delete $link->{+LOCAL_COLUMNS} // delete $link->{local_fields} // delete $link->{local};
      0        
133 0   0       my $other_columns = delete $link->{+OTHER_COLUMNS} // delete $link->{other_fields} // delete $link->{other};
      0        
134              
135 0           my @keys = keys %$link;
136 0 0         if (@keys == 1) {
137 0           ($other_table) = @keys;
138 0           my $val = delete $link->{$other_table};
139              
140 0 0         croak "You must provide an arrayref of columns" unless $val;
141              
142 0           my $cref = ref($val);
143 0 0         unless ($cref) {
144 0           $val = [$val];
145 0           $cref = 'ARRAY';
146             }
147              
148 0 0         if ($cref eq 'ARRAY') {
    0          
149 0   0       $local_columns //= $val;
150 0   0       $other_columns //= $val;
151             }
152             elsif ($cref eq 'HASH') {
153 0           %$link = (%$link, %$val);
154 0   0       $local_columns = delete $link->{+LOCAL_COLUMNS} // delete $link->{local_fields} // delete $link->{local};
      0        
155 0   0       $other_columns = delete $link->{+OTHER_COLUMNS} // delete $link->{other_fields} // delete $link->{other};
      0        
156             }
157             }
158              
159 0 0 0       $local_table //= $source ? $source->name : croak "No local_table or source provided";
160 0 0         croak "no other_table provided" unless $other_table;
161              
162 0           my ($local, $other);
163 0 0         if ($schema) {
164 0 0         $local = $schema->table($local_table) or croak "local table '$local_table' does not exist in the provided schema";
165 0 0         $other = $schema->table($other_table) or croak "other table '$other_table' does not exist in the provided schema";
166             }
167              
168 0   0       $local_columns //= $fields // croak "no local_columns provided";
      0        
169 0   0       $other_columns //= $fields // croak "no other_columns provided";
      0        
170              
171 0 0         $local_columns = [$local_columns] unless ref $local_columns;
172 0 0         $other_columns = [$other_columns] unless ref $other_columns;
173              
174 0 0 0       croak "expected an arrayref in 'local_columns' got '$local_columns'" unless ref($local_columns) eq 'ARRAY' && @$local_columns;
175 0 0 0       croak "expected an arrayref in 'other_columns' got '$other_columns'" unless ref($other_columns) eq 'ARRAY' && @$other_columns;
176              
177 0           my $unique = $link->{+UNIQUE};
178 0 0 0       $unique //= $other->unique->{column_key(@$other_columns)} ? 1 : 0 if $other;
    0          
179 0 0         croak "'unique' not defined, and no schema provided to check" unless defined $unique;
180              
181 0           return $class->new(
182             LOCAL_TABLE() => $local_table,
183             OTHER_TABLE() => $other_table,
184             LOCAL_COLUMNS() => $local_columns,
185             OTHER_COLUMNS() => $other_columns,
186             UNIQUE() => $unique,
187             );
188             }
189              
190             1;