File Coverage

blib/lib/SQL/Translator/Schema/Trigger.pm
Criterion Covered Total %
statement 33 36 91.6
branch 7 14 50.0
condition 2 6 33.3
subroutine 9 9 100.0
pod 4 4 100.0
total 55 69 79.7


line stmt bran cond sub pod time code
1             package SQL::Translator::Schema::Trigger;
2              
3             =pod
4              
5             =head1 NAME
6              
7             SQL::Translator::Schema::Trigger - SQL::Translator trigger object
8              
9             =head1 SYNOPSIS
10              
11             use SQL::Translator::Schema::Trigger;
12             my $trigger = SQL::Translator::Schema::Trigger->new(
13             name => 'foo',
14             perform_action_when => 'before', # or after
15             database_events => [qw/update insert/], # also update, update_on, delete
16             fields => [], # if event is "update"
17             on_table => 'foo', # table name
18             action => '...', # text of trigger
19             schema => $schema, # Schema object
20             scope => 'row', # or statement
21             );
22              
23             =head1 DESCRIPTION
24              
25             C is the trigger object.
26              
27             =head1 METHODS
28              
29             =cut
30              
31 70     70   432 use Moo;
  70         184  
  70         462  
32 70     70   21084 use SQL::Translator::Utils qw(parse_list_arg ex2err throw uniq);
  70         208  
  70         5098  
33 70     70   426 use SQL::Translator::Types qw(schema_obj enum);
  70         1326  
  70         4075  
34 70     70   517 use Sub::Quote qw(quote_sub);
  70         143  
  70         67263  
35              
36             extends 'SQL::Translator::Schema::Object';
37              
38             our $VERSION = '1.6_3';
39              
40             =head2 new
41              
42             Object constructor.
43              
44             my $schema = SQL::Translator::Schema::Trigger->new;
45              
46             =cut
47              
48             around BUILDARGS => sub {
49             my ($orig, $self, @args) = @_;
50             my $args = $self->$orig(@args);
51             if (exists $args->{on_table}) {
52             my $arg = delete $args->{on_table};
53             my $table = $args->{schema}->get_table($arg)
54             or die "Table named $arg doesn't exist";
55             $args->{table} = $table;
56             }
57             if (exists $args->{database_event}) {
58             $args->{database_events} = delete $args->{database_event};
59             }
60             return $args;
61             };
62              
63             =head2 perform_action_when
64              
65             Gets or sets whether the event happens "before" or "after" the
66             C.
67              
68             $trigger->perform_action_when('after');
69              
70             =cut
71              
72             has perform_action_when => (
73             is => 'rw',
74             coerce => quote_sub(q{ defined $_[0] ? lc $_[0] : $_[0] }),
75             isa => enum([qw(before after)], {
76             msg => "Invalid argument '%s' to perform_action_when",
77             allow_undef => 1,
78             }),
79             );
80              
81             around perform_action_when => \&ex2err;
82              
83             sub database_event {
84              
85             =pod
86              
87             =head2 database_event
88              
89             Obsolete please use database_events!
90              
91             =cut
92              
93 2     2 1 3 my $self = shift;
94              
95 2         33 return $self->database_events( @_ );
96             }
97              
98             =head2 database_events
99              
100             Gets or sets the events that triggers the trigger.
101              
102             my $ok = $trigger->database_events('insert');
103              
104             =cut
105              
106             has database_events => (
107             is => 'rw',
108             coerce => quote_sub(q{ [ map { lc } ref $_[0] eq 'ARRAY' ? @{$_[0]} : ($_[0]) ] }),
109             isa => sub {
110             my @args = @{$_[0]};
111             my %valid = map { $_, 1 } qw[ insert update update_on delete ];
112             my @invalid = grep { !defined $valid{ $_ } } @args;
113              
114             if ( @invalid ) {
115             throw(
116             sprintf("Invalid events '%s' in database_events",
117             join(', ', @invalid)
118             )
119             );
120             }
121             },
122             );
123              
124             around database_events => sub {
125             my ($orig,$self) = (shift, shift);
126              
127             if (@_) {
128             ex2err($orig, $self, ref $_[0] eq 'ARRAY' ? $_[0] : \@_)
129             or return;
130             }
131              
132             return wantarray
133             ? @{ $self->$orig || [] }
134             : $self->$orig;
135             };
136              
137             =head2 fields
138              
139             Gets and set which fields to monitor for C.
140              
141             $view->fields('id');
142             $view->fields('id', 'name');
143             $view->fields( 'id, name' );
144             $view->fields( [ 'id', 'name' ] );
145             $view->fields( qw[ id name ] );
146              
147             my @fields = $view->fields;
148              
149             =cut
150              
151             has fields => (
152             is => 'rw',
153             coerce => sub {
154             my @fields = uniq @{parse_list_arg($_[0])};
155             @fields ? \@fields : undef;
156             },
157             );
158              
159             around fields => sub {
160             my $orig = shift;
161             my $self = shift;
162             my $fields = parse_list_arg( @_ );
163             $self->$orig($fields) if @$fields;
164              
165             return wantarray ? @{ $self->$orig || [] } : $self->$orig;
166             };
167              
168             =head2 table
169              
170             Gets or set the table on which the trigger works, as a L object.
171             $trigger->table($triggered_table);
172              
173             =cut
174              
175             has table => ( is => 'rw', isa => schema_obj('Table'), weak_ref => 1 );
176              
177             around table => \&ex2err;
178              
179             sub on_table {
180              
181             =pod
182              
183             =head2 on_table
184              
185             Gets or set the table name on which the trigger works, as a string.
186             $trigger->on_table('foo');
187              
188             =cut
189              
190 81     81 1 507 my ($self, $arg) = @_;
191 81 50       213 if ( @_ == 2 ) {
192 0         0 my $table = $self->schema->get_table($arg);
193 0 0       0 die "Table named $arg doesn't exist"
194             if !$table;
195 0         0 $self->table($table);
196             }
197 81         1333 return $self->table->name;
198             }
199              
200             =head2 action
201              
202             Gets or set the action of the trigger.
203              
204             $trigger->action(
205             q[
206             BEGIN
207             select ...;
208             update ...;
209             END
210             ]
211             );
212              
213             =cut
214              
215             has action => ( is => 'rw', default => quote_sub(q{ '' }) );
216              
217             sub is_valid {
218              
219             =pod
220              
221             =head2 is_valid
222              
223             Determine whether the trigger is valid or not.
224              
225             my $ok = $trigger->is_valid;
226              
227             =cut
228              
229 2     2 1 5 my $self = shift;
230              
231 2         4 for my $attr (
232             qw[ name perform_action_when database_events on_table action ]
233             ) {
234 10 50       183 return $self->error("Invalid: missing '$attr'") unless $self->$attr();
235             }
236              
237 2 50 33     7 return $self->error("Missing fields for UPDATE ON") if
238             $self->database_event eq 'update_on' && !$self->fields;
239              
240 2         25 return 1;
241             }
242              
243             =head2 name
244              
245             Get or set the trigger's name.
246              
247             my $name = $trigger->name('foo');
248              
249             =cut
250              
251             has name => ( is => 'rw', default => quote_sub(q{ '' }) );
252              
253             =head2 order
254              
255             Get or set the trigger's order.
256              
257             my $order = $trigger->order(3);
258              
259             =cut
260              
261             has order => ( is => 'rw', default => quote_sub(q{ 0 }) );
262              
263             around order => sub {
264             my ( $orig, $self, $arg ) = @_;
265              
266             if ( defined $arg && $arg =~ /^\d+$/ ) {
267             return $self->$orig($arg);
268             }
269              
270             return $self->$orig;
271             };
272              
273             =head2 scope
274              
275             Get or set the trigger's scope (row or statement).
276              
277             my $scope = $trigger->scope('statement');
278              
279             =cut
280              
281             has scope => (
282             is => 'rw',
283             isa => enum([qw(row statement)], {
284             msg => "Invalid scope '%s'", icase => 1, allow_undef => 1,
285             }),
286             );
287              
288             around scope => \&ex2err;
289              
290              
291             =head2 schema
292              
293             Get or set the trigger's schema object.
294              
295             $trigger->schema( $schema );
296             my $schema = $trigger->schema;
297              
298             =cut
299              
300             has schema => (is => 'rw', isa => schema_obj('Schema'), weak_ref => 1 );
301              
302             around schema => \&ex2err;
303              
304             sub compare_arrays {
305              
306             =pod
307              
308             =head2 compare_arrays
309              
310             Compare two arrays.
311              
312             =cut
313              
314 3     3 1 21 my ($first, $second) = @_;
315 70     70   568 no warnings; # silence spurious -w undef complaints
  70         150  
  70         23365  
316              
317 3 50 33     16 return 0 unless (ref $first eq 'ARRAY' and ref $second eq 'ARRAY' ) ;
318              
319 3 100       9 return 0 unless @$first == @$second;
320              
321 2         9 my @first = sort @$first;
322              
323 2         4 my @second = sort @$second;
324              
325 2         6 for (my $i = 0; $i < scalar @first; $i++) {
326 3 50       10 return 0 if @first[$i] ne @second[$i];
327             }
328              
329 2         6 return 1;
330             }
331              
332             =head2 equals
333              
334             Determines if this trigger is the same as another
335              
336             my $is_identical = $trigger1->equals( $trigger2 );
337              
338             =cut
339              
340             around equals => sub {
341             my $orig = shift;
342             my $self = shift;
343             my $other = shift;
344             my $case_insensitive = shift;
345              
346             return 0 unless $self->$orig($other);
347              
348             my %names;
349             for my $name ( $self->name, $other->name ) {
350             $name = lc $name if $case_insensitive;
351             $names{ $name }++;
352             }
353              
354             if ( keys %names > 1 ) {
355             return $self->error('Names not equal');
356             }
357              
358             if ( !$self->perform_action_when eq $other->perform_action_when ) {
359             return $self->error('perform_action_when differs');
360             }
361              
362             if (
363             !compare_arrays( [$self->database_events], [$other->database_events] )
364             ) {
365             return $self->error('database_events differ');
366             }
367              
368             if ( $self->on_table ne $other->on_table ) {
369             return $self->error('on_table differs');
370             }
371              
372             if ( $self->action ne $other->action ) {
373             return $self->error('action differs');
374             }
375              
376             if (
377             !$self->_compare_objects( scalar $self->extra, scalar $other->extra )
378             ) {
379             return $self->error('extras differ');
380             }
381              
382             return 1;
383             };
384              
385             # Must come after all 'has' declarations
386             around new => \&ex2err;
387              
388             1;
389              
390             =pod
391              
392             =head1 AUTHORS
393              
394             Anonymous,
395             Ken Youens-Clark Ekclark@cpan.orgE.
396              
397             =cut