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