Allow passing an arrayref to SQLT->filename
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Schema / Index.pm
CommitLineData
3c5de62a 1package SQL::Translator::Schema::Index;
2
3c5de62a 3=pod
4
5=head1 NAME
6
7SQL::Translator::Schema::Index - SQL::Translator index object
8
9=head1 SYNOPSIS
10
11 use SQL::Translator::Schema::Index;
12 my $index = SQL::Translator::Schema::Index->new(
13 name => 'foo',
14 fields => [ id ],
15 type => 'unique',
16 );
17
18=head1 DESCRIPTION
19
20C<SQL::Translator::Schema::Index> is the index object.
21
b54199ae 22Primary and unique keys are table constraints, not indices.
3c5de62a 23
24=head1 METHODS
25
26=cut
27
90097ddd 28use Moo;
25868dc9 29use SQL::Translator::Schema::Constants;
0fb58589 30use SQL::Translator::Utils qw(ex2err throw);
31use SQL::Translator::Role::ListAttr;
4c3f67fa 32use SQL::Translator::Types qw(schema_obj enum);
68d75205 33use Sub::Quote qw(quote_sub);
3c5de62a 34
954ed12e 35extends 'SQL::Translator::Schema::Object';
b6a880d1 36
0c04c5a2 37our $VERSION = '1.59';
3c5de62a 38
11ad2df9 39my %VALID_INDEX_TYPE = (
40 UNIQUE => 1,
41 NORMAL => 1,
42 FULLTEXT => 1, # MySQL only (?)
43 FULL_TEXT => 1, # MySQL only (?)
44 SPATIAL => 1, # MySQL only (?)
c8efc003 45);
3c5de62a 46
3c5de62a 47=head2 new
48
49Object constructor.
50
51 my $schema = SQL::Translator::Schema::Index->new;
52
3c5de62a 53=head2 fields
54
b54199ae 55Gets and set the fields the index is on. Accepts a string, list or
25868dc9 56arrayref; returns an array or array reference. Will unique the field
57names and keep them in order by the first occurrence of a field name.
3c5de62a 58
b54199ae 59 $index->fields('id');
60 $index->fields('id', 'name');
61 $index->fields( 'id, name' );
62 $index->fields( [ 'id', 'name' ] );
63 $index->fields( qw[ id name ] );
25868dc9 64
b54199ae 65 my @fields = $index->fields;
3c5de62a 66
67=cut
68
0fb58589 69with ListAttr fields => ( uniq => 1 );
3c5de62a 70
b54199ae 71sub is_valid {
72
73=pod
74
75=head2 is_valid
76
77Determine whether the index is valid or not.
78
79 my $ok = $index->is_valid;
80
81=cut
82
83 my $self = shift;
84 my $table = $self->table or return $self->error('No table');
85 my @fields = $self->fields or return $self->error('No fields');
86
87 for my $field ( @fields ) {
88 return $self->error(
89 "Field '$field' does not exist in table '", $table->name, "'"
90 ) unless $table->get_field( $field );
91 }
92
93 return 1;
94}
95
3c5de62a 96=head2 name
97
98Get or set the index's name.
99
100 my $name = $index->name('foo');
101
102=cut
103
9593ed04 104has name => (
105 is => 'rw',
106 coerce => quote_sub(q{ defined $_[0] ? $_[0] : '' }),
107 default => quote_sub(q{ '' }),
108);
25868dc9 109
110=head2 options
111
112Get or set the index's options (e.g., "using" or "where" for PG). Returns
113an array or array reference.
114
115 my @options = $index->options;
116
117=cut
118
0fb58589 119with ListAttr options => ();
43b9dc7a 120
121=head2 table
122
123Get or set the index's table object.
124
125 my $table = $index->table;
126
127=cut
128
a5bfeba8 129has table => ( is => 'rw', isa => schema_obj('Table'), weak_ref => 1 );
43b9dc7a 130
45287c81 131around table => \&ex2err;
3c5de62a 132
133=head2 type
134
135Get or set the index's type.
136
137 my $type = $index->type('unique');
138
d06db857 139Get or set the index's type.
19ad0cee 140
141Currently there are only four acceptable types: UNIQUE, NORMAL, FULL_TEXT,
142and SPATIAL. The latter two might be MySQL-specific. While both lowercase
143and uppercase types are acceptable input, this method returns the type in
144uppercase.
145
3c5de62a 146=cut
147
45287c81 148has type => (
149 is => 'rw',
c804300c 150 coerce => quote_sub(q{ uc $_[0] }),
68d75205 151 default => quote_sub(q{ 'NORMAL' }),
4c3f67fa 152 isa => enum([keys %VALID_INDEX_TYPE], {
153 msg => "Invalid index type: %s", allow_false => 1,
154 }),
45287c81 155);
3c5de62a 156
45287c81 157around type => \&ex2err;
abf315bb 158
159=head2 equals
160
161Determines if this index is the same as another
162
163 my $isIdentical = $index1->equals( $index2 );
164
165=cut
166
2cb3ea55 167around equals => sub {
168 my $orig = shift;
abf315bb 169 my $self = shift;
170 my $other = shift;
171 my $case_insensitive = shift;
d990d84b 172 my $ignore_index_names = shift;
ea93df61 173
2cb3ea55 174 return 0 unless $self->$orig($other);
da5a1bae 175
d990d84b 176 unless ($ignore_index_names) {
da5a1bae 177 unless ((!$self->name && ($other->name eq $other->fields->[0])) ||
178 (!$other->name && ($self->name eq $self->fields->[0]))) {
d990d84b 179 return 0 unless $case_insensitive ? uc($self->name) eq uc($other->name) : $self->name eq $other->name;
da5a1bae 180 }
d990d84b 181 }
82f6b50e 182 #return 0 unless $self->is_valid eq $other->is_valid;
abf315bb 183 return 0 unless $self->type eq $other->type;
ea93df61 184
c243ec2b 185 # Check fields, regardless of order
ea93df61 186 my %otherFields = (); # create a hash of the other fields
c243ec2b 187 foreach my $otherField ($other->fields) {
ea93df61 188 $otherField = uc($otherField) if $case_insensitive;
189 $otherFields{$otherField} = 1;
c243ec2b 190 }
191 foreach my $selfField ($self->fields) { # check for self fields in hash
ea93df61 192 $selfField = uc($selfField) if $case_insensitive;
193 return 0 unless $otherFields{$selfField};
194 delete $otherFields{$selfField};
c243ec2b 195 }
196 # Check all other fields were accounted for
197 return 0 unless keys %otherFields == 0;
198
4598b71c 199 return 0 unless $self->_compare_objects(scalar $self->options, scalar $other->options);
200 return 0 unless $self->_compare_objects(scalar $self->extra, scalar $other->extra);
abf315bb 201 return 1;
2cb3ea55 202};
3c5de62a 203
45287c81 204# Must come after all 'has' declarations
205around new => \&ex2err;
206
3c5de62a 2071;
208
3c5de62a 209=pod
210
211=head1 AUTHOR
212
c3b0b535 213Ken Youens-Clark E<lt>kclark@cpan.orgE<gt>.
3c5de62a 214
215=cut