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