Reinstate schema object base class
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Schema / View.pm
1 package SQL::Translator::Schema::View;
2
3 =pod
4
5 =head1 NAME
6
7 SQL::Translator::Schema::View - SQL::Translator view object
8
9 =head1 SYNOPSIS
10
11   use SQL::Translator::Schema::View;
12   my $view   = SQL::Translator::Schema::View->new(
13       name   => 'foo',                      # name, required
14       sql    => 'select id, name from foo', # SQL for view
15       fields => 'id, name',                 # field names in view
16   );
17
18 =head1 DESCRIPTION
19
20 C<SQL::Translator::Schema::View> is the view object.
21
22 =head1 METHODS
23
24 =cut
25
26 use Moo;
27 use SQL::Translator::Utils qw(parse_list_arg ex2err);
28 use SQL::Translator::Types qw(schema_obj);
29 use List::MoreUtils qw(uniq);
30
31 extends 'SQL::Translator::Schema::Object';
32
33 our $VERSION = '1.59';
34
35 =head2 new
36
37 Object constructor.
38
39   my $view = SQL::Translator::Schema::View->new;
40
41 =head2 fields
42
43 Gets and set the fields the constraint is on.  Accepts a string, list or
44 arrayref; returns an array or array reference.  Will unique the field
45 names and keep them in order by the first occurrence of a field name.
46
47   $view->fields('id');
48   $view->fields('id', 'name');
49   $view->fields( 'id, name' );
50   $view->fields( [ 'id', 'name' ] );
51   $view->fields( qw[ id name ] );
52
53   my @fields = $view->fields;
54
55 =cut
56
57 has fields => (
58     is => 'rw',
59     default => sub { [] },
60     coerce => sub { [uniq @{parse_list_arg($_[0])}] },
61 );
62
63 around fields => sub {
64     my $orig   = shift;
65     my $self   = shift;
66     my $fields = parse_list_arg( @_ );
67     $self->$orig($fields) if @$fields;
68
69     return wantarray ? @{ $self->$orig } : $self->$orig;
70 };
71
72 =head2 tables
73
74 Gets and set the tables the SELECT mentions.  Accepts a string, list or
75 arrayref; returns an array or array reference.  Will unique the table
76 names and keep them in order by the first occurrence of a field name.
77
78   $view->tables('foo');
79   $view->tables('foo', 'bar');
80   $view->tables( 'foo, bar' );
81   $view->tables( [ 'foo', 'bar' ] );
82   $view->tables( qw[ foo bar ] );
83
84   my @tables = $view->tables;
85
86 =cut
87
88 has tables => (
89     is => 'rw',
90     default => sub { [] },
91     coerce => sub { [uniq @{parse_list_arg($_[0])}] },
92 );
93
94 around tables => sub {
95     my $orig   = shift;
96     my $self   = shift;
97     my $fields = parse_list_arg( @_ );
98     $self->$orig($fields) if @$fields;
99
100     return wantarray ? @{ $self->$orig } : $self->$orig;
101 };
102
103 =head2 options
104
105 Gets and sets a list of options on the view.
106
107   $view->options('ALGORITHM=UNDEFINED');
108
109   my @options = $view->options;
110
111 =cut
112
113 has options => (
114     is => 'rw',
115     default => sub { [] },
116     coerce => sub { [uniq @{parse_list_arg($_[0])}] },
117 );
118
119 around options => sub {
120     my $orig    = shift;
121     my $self    = shift;
122     my $options = parse_list_arg( @_ );
123
124     if ( @$options ) {
125         $self->$orig([ @{$self->$orig}, @$options ])
126     }
127
128     return wantarray ? @{ $self->$orig } : $self->$orig;
129 };
130
131 sub is_valid {
132
133 =pod
134
135 =head2 is_valid
136
137 Determine whether the view is valid or not.
138
139   my $ok = $view->is_valid;
140
141 =cut
142
143     my $self = shift;
144
145     return $self->error('No name') unless $self->name;
146     return $self->error('No sql')  unless $self->sql;
147
148     return 1;
149 }
150
151 =head2 name
152
153 Get or set the view's name.
154
155   my $name = $view->name('foo');
156
157 =cut
158
159 has name => ( is => 'rw', default => sub { '' } );
160
161 =head2 order
162
163 Get or set the view's order.
164
165   my $order = $view->order(3);
166
167 =cut
168
169 has order => ( is => 'rw', default => sub { 0 } );
170
171 around order => sub {
172     my ( $orig, $self, $arg ) = @_;
173
174     if ( defined $arg && $arg =~ /^\d+$/ ) {
175         return $self->$orig($arg);
176     }
177
178     return $self->$orig;
179 };
180
181 =head2 sql
182
183 Get or set the view's SQL.
184
185   my $sql = $view->sql('select * from foo');
186
187 =cut
188
189 has sql => ( is => 'rw', default => sub { '' } );
190
191 =head2 schema
192
193 Get or set the view's schema object.
194
195   $view->schema( $schema );
196   my $schema = $view->schema;
197
198 =cut
199
200 has schema => ( is => 'rw', isa => schema_obj('Schema'), weak_ref => 1 );
201
202 around schema => \&ex2err;
203
204 =head2 equals
205
206 Determines if this view is the same as another
207
208   my $isIdentical = $view1->equals( $view2 );
209
210 =cut
211
212 around equals => sub {
213     my $orig = shift;
214     my $self = shift;
215     my $other = shift;
216     my $case_insensitive = shift;
217     my $ignore_sql = shift;
218
219     return 0 unless $self->$orig($other);
220     return 0 unless $case_insensitive ? uc($self->name) eq uc($other->name) : $self->name eq $other->name;
221     #return 0 unless $self->is_valid eq $other->is_valid;
222
223     unless ($ignore_sql) {
224         my $selfSql = $self->sql;
225         my $otherSql = $other->sql;
226         # Remove comments
227         $selfSql =~ s/--.*$//mg;
228         $otherSql =~ s/--.*$//mg;
229         # Collapse whitespace to space to avoid whitespace comparison issues
230         $selfSql =~ s/\s+/ /sg;
231         $otherSql =~ s/\s+/ /sg;
232         return 0 unless $selfSql eq $otherSql;
233     }
234
235     my $selfFields = join(":", $self->fields);
236     my $otherFields = join(":", $other->fields);
237     return 0 unless $case_insensitive ? uc($selfFields) eq uc($otherFields) : $selfFields eq $otherFields;
238     return 0 unless $self->_compare_objects(scalar $self->extra, scalar $other->extra);
239     return 1;
240 };
241
242 # Must come after all 'has' declarations
243 around new => \&ex2err;
244
245 1;
246
247 =pod
248
249 =head1 AUTHOR
250
251 Ken Youens-Clark E<lt>kclark@cpan.orgE<gt>.
252
253 =cut