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