comparison Lib/IMPL/SQL/Schema/Table.pm @ 165:76515373dac0

Added Class::Template, Rewritten SQL::Schema 'use parent' directive instead of 'use base'
author wizard
date Sat, 23 Apr 2011 23:06:48 +0400
parents 6ce1f052b90a
children 1f7a6d762394
comparison
equal deleted inserted replaced
164:eb3e9861a761 165:76515373dac0
1 use strict; 1 use strict;
2 package IMPL::SQL::Schema::Table; 2 package IMPL::SQL::Schema::Table;
3 3
4 use IMPL::SQL::Schema::Column; 4 use IMPL::lang;
5 use IMPL::SQL::Schema::Constraint; 5
6 use IMPL::SQL::Schema::Constraint::PrimaryKey; 6 use parent qw(
7 use IMPL::SQL::Schema::Constraint::ForeignKey;
8
9 use base qw(
10 IMPL::Object 7 IMPL::Object
11 IMPL::Object::Disposable 8 IMPL::Object::Disposable
12 IMPL::Object::Clonable
13 ); 9 );
10
11 use IMPL::SQL::Schema::Column();
12 use IMPL::SQL::Schema::Constraint();
13 use IMPL::SQL::Schema::Constraint::PrimaryKey();
14 use IMPL::SQL::Schema::Constraint::ForeignKey();
15
14 use IMPL::Class::Property; 16 use IMPL::Class::Property;
15 use IMPL::Class::Property::Direct; 17 use IMPL::Class::Property::Direct;
16 18
17 BEGIN { 19 BEGIN {
18 public _direct property Name => prop_get; 20 public _direct property name => prop_get;
19 public _direct property Schema => prop_get; 21 public _direct property schema => prop_get;
20 public _direct property Columns => prop_get; 22 public _direct property columns => prop_get;
21 public _direct property Constraints => prop_get; 23 public _direct property constraints => prop_get;
22 public _direct property ColumnsByName => prop_none; 24 public _direct property columnsByName => prop_none;
23 public _direct property PrimaryKey => prop_get; 25 public _direct property primaryKey => prop_get;
24 public _direct property Tag => prop_all; 26 public _direct property tag => prop_all;
25 } 27 }
26 28
27 sub CTOR { 29 sub CTOR {
28 my ($this,%args) = @_; 30 my ($this,%args) = @_;
29 31
30 $this->{$Name} = $args{'Name'} or die new IMPL::InvalidArgumentException('a table name is required'); 32 $this->{$name} = $args{'name'} or die new IMPL::InvalidArgumentException('a table name is required');
31 $this->{$Schema} = $args{'Schema'} or die new IMPL::InvalidArgumentException('a parent schema is required'); 33 $this->{$schema} = $args{'schema'} or die new IMPL::InvalidArgumentException('a parent schema is required');
34
35 if ($args{columns}) {
36 die new IMPL::InvalidOperationException('A columns property should be a reference to an array') unless ref $args{columns} eq 'ARRAY';
37
38 $this->InsertColumn($_) foreach @{$args{columns}};
39 }
40
41 if ($args{constraints}) {
42 die new IMPL::InvalidOperationException('A constraints property should be a reference to an array') unless ref $args{constraints} eq 'ARRAY';
43
44 $this->AddConstraint($_) foreach @{$args{constraints}};
45 }
32 } 46 }
33 47
34 sub InsertColumn { 48 sub InsertColumn {
35 my ($this,$column,$index) = @_; 49 my ($this,$column,$index) = @_;
36 50
37 $index = ($this->{$Columns} ? scalar(@{$this->{$Columns}}) : 0) if not defined $index; 51 $index = ($this->{$columns} ? scalar(@{$this->{$columns}}) : 0) if not defined $index;
38 52
39 die new IMPL::InvalidArgumentException("The index is out of range") if ($index < 0 || $index > ($this->{$Columns} ? scalar(@{$this->{$Columns}}) : 0)); 53 die new IMPL::InvalidArgumentException("The index is out of range") if ($index < 0 || $index > ($this->{$columns} ? scalar(@{$this->{$columns}}) : 0));
40 54
41 if (UNIVERSAL::isa($column,'IMPL::SQL::Schema::Column')) { 55 if (UNIVERSAL::isa($column,'IMPL::SQL::Schema::Column')) {
42 56
43 } elsif (UNIVERSAL::isa($column,'HASH')) { 57 } elsif (UNIVERSAL::isa($column,'HASH')) {
44 $column = new IMPL::SQL::Schema::Column(%{$column}); 58 $column = new IMPL::SQL::Schema::Column(%{$column});
45 } else { 59 } else {
46 die new IMPL::InvalidArgumentException("The invalid column parameter"); 60 die new IMPL::InvalidArgumentException("The invalid column parameter");
47 } 61 }
48 62
49 if (exists $this->{$ColumnsByName}->{$column->Name}) { 63 if (exists $this->{$columnsByName}->{$column->name}) {
50 die new IMPL::InvalidOperationException("The column already exists",$column->name); 64 die new IMPL::InvalidOperationException("The column already exists",$column->name);
51 } else { 65 } else {
52 $this->{$ColumnsByName}->{$column->Name} = $column; 66 $this->{$columnsByName}->{$column->name} = $column;
53 splice @{$this->{$Columns}},$index,0,$column; 67 splice @{$this->{$columns}},$index,0,$column;
54 } 68 }
55 69
56 return $column; 70 return $column;
57 } 71 }
58 72
59 sub RemoveColumn { 73 sub RemoveColumn {
60 my ($this,$NameOrColumn,$Force) = @_; 74 my ($this,$NameOrColumn,$Force) = @_;
61 75
62 my $ColName; 76 my $ColName;
63 if (UNIVERSAL::isa($NameOrColumn,'IMPL::SQL::Schema::Column')) { 77 if (UNIVERSAL::isa($NameOrColumn,'IMPL::SQL::Schema::Column')) {
64 $ColName = $NameOrColumn->Name; 78 $ColName = $NameOrColumn->name;
65 } elsif (not ref $NameOrColumn) { 79 } elsif (not ref $NameOrColumn) {
66 $ColName = $NameOrColumn; 80 $ColName = $NameOrColumn;
67 } 81 }
68 82
69 if (exists $this->{$ColumnsByName}->{$ColName}) { 83 if (exists $this->{$columnsByName}->{$ColName}) {
70 my $index = 0; 84 my $index = 0;
71 foreach my $column(@{$this->{$Columns}}) { 85 foreach my $column(@{$this->{$columns}}) {
72 last if $column->Name eq $ColName; 86 last if $column->name eq $ColName;
73 $index++; 87 $index++;
74 } 88 }
75 89
76 my $column = $this->{$Columns}[$index]; 90 my $column = $this->{$columns}[$index];
77 if (my @constraints = $this->GetColumnConstraints($column)){ 91 if (my @constraints = $this->GetColumnConstraints($column)){
78 $Force or die new IMPL::InvalidOperationException('Can\'t remove column which is used in the constraints',@constraints); 92 $Force or die new IMPL::InvalidOperationException('Can\'t remove column which is used in the constraints',@constraints);
79 $this->RemoveConstraint($_) foreach @constraints; 93 $this->RemoveConstraint($_) foreach @constraints;
80 } 94 }
81 95
82 my $removed = splice @{$this->{$Columns}},$index,1; 96 my $removed = splice @{$this->{$columns}},$index,1;
83 delete $this->{$ColumnsByName}->{$ColName}; 97 delete $this->{$columnsByName}->{$ColName};
84 return $removed; 98 return $removed;
85 } else { 99 } else {
86 die new IMPL::InvalidOperationException("The column not found",$NameOrColumn->Name); 100 die new IMPL::InvalidOperationException("The column not found",$NameOrColumn->name);
87 } 101 }
88 } 102 }
89 103
90 sub Column { 104 sub Column {
91 my ($this,$name) = @_; 105 my ($this,$name) = @_;
92 106
93 return $this->{$ColumnsByName}->{$name}; 107 return $this->{$columnsByName}->{$name};
94 } 108 }
95 109
96 sub ColumnAt { 110 sub ColumnAt {
97 my ($this,$index) = @_; 111 my ($this,$index) = @_;
98 112
99 die new IMPL::InvalidArgumentException("The index is out of range") if $index < 0 || $index >= ($this->{$Columns} ? scalar(@{$this->{$Columns}}) : 0); 113 die new IMPL::InvalidArgumentException("The index is out of range")
100 114 if $index < 0 || $index >= ($this->{$columns} ? scalar(@{$this->{$columns}}) : 0);
101 return $this->{$Columns}[$index]; 115
116 return $this->{$columns}[$index];
117 }
118
119 sub ColumnsCount {
120 my ($this) = @_;
121
122 return scalar(@{$this->{$columns}});
102 } 123 }
103 124
104 sub AddConstraint { 125 sub AddConstraint {
105 my ($this,$Constraint) = @_; 126 my ($this,$Constraint) = @_;
106 127
107 die new IMPL::InvalidArgumentException('The invalid parameter') if not UNIVERSAL::isa($Constraint,'IMPL::SQL::Schema::Constraint'); 128 if (ref $Constraint eq 'HASH') {
108 129 $Constraint = new IMPL::SQL::Schema::Constraint( %$Constraint, table => $this );
109 $Constraint->Table == $this or die new IMPL::InvalidOperationException('The constaint must belong to the target table'); 130 } else {
110 131 die new IMPL::InvalidArgumentException('The invalid parameter') if not is($Constraint,typeof IMPL::SQL::Schema::Constraint);
111 if (exists $this->{$Constraints}->{$Constraint->Name}) { 132 }
112 die new IMPL::InvalidOperationException('The table already has the specified constraint',$Constraint->Name); 133
134 $Constraint->table == $this or die new IMPL::InvalidOperationException('The constaint must belong to the target table');
135
136 if (exists $this->{$constraints}->{$Constraint->name}) {
137 die new IMPL::InvalidOperationException('The table already has the specified constraint',$Constraint->name);
113 } else { 138 } else {
114 if (UNIVERSAL::isa($Constraint,'IMPL::SQL::Schema::Constraint::PrimaryKey')) { 139 if (UNIVERSAL::isa($Constraint,'IMPL::SQL::Schema::Constraint::PrimaryKey')) {
115 not $this->{$PrimaryKey} or die new IMPL::InvalidOperationException('The table already has a primary key'); 140 not $this->{$primaryKey} or die new IMPL::InvalidOperationException('The table already has a primary key');
116 $this->{$PrimaryKey} = $Constraint; 141 $this->{$primaryKey} = $Constraint;
117 } 142 }
118 143
119 $this->{$Constraints}->{$Constraint->Name} = $Constraint; 144 $this->{$constraints}->{$Constraint->name} = $Constraint;
120 } 145 }
121 } 146 }
122 147
123 sub RemoveConstraint { 148 sub RemoveConstraint {
124 my ($this,$Constraint,$Force) = @_; 149 my ($this,$Constraint,$Force) = @_;
125 150
126 my $cn = UNIVERSAL::isa($Constraint,'IMPL::SQL::Schema::Constraint') ? $Constraint->Name : $Constraint; 151 my $cn = UNIVERSAL::isa($Constraint,'IMPL::SQL::Schema::Constraint') ? $Constraint->name : $Constraint;
127 $Constraint = $this->{$Constraints}->{$cn} or die new IMPL::InvalidOperationException('The specified constraint doesn\'t exists',$cn); 152 $Constraint = $this->{$constraints}->{$cn} or die new IMPL::InvalidOperationException('The specified constraint doesn\'t exists',$cn);
128 153
129 if (UNIVERSAL::isa($Constraint,'IMPL::SQL::Schema::Constraint::PrimaryKey')) { 154 if (UNIVERSAL::isa($Constraint,'IMPL::SQL::Schema::Constraint::PrimaryKey')) {
130 not scalar keys %{$this->{$PrimaryKey}->ConnectedFK} or die new IMPL::InvalidOperationException('Can\'t remove Primary Key unless some foreign keys referenses it'); 155 not scalar keys %{$this->{$primaryKey}->ConnectedFK} or die new IMPL::InvalidOperationException('Can\'t remove Primary Key unless some foreign keys referenses it');
131 156
132 delete $this->{$PrimaryKey}; 157 delete $this->{$primaryKey};
133 } 158 }
134 $Constraint->Dispose; 159 $Constraint->Dispose;
135 delete $this->{$Constraints}->{$cn}; 160 delete $this->{$constraints}->{$cn};
136 return $cn; 161 return $cn;
162 }
163
164 sub GetConstraint {
165 my ($this,$name) = @_;
166
167 return $this->{$constraints}{$name};
137 } 168 }
138 169
139 sub GetColumnConstraints { 170 sub GetColumnConstraints {
140 my ($this,@Columns) = @_; 171 my ($this,@Columns) = @_;
141 172
142 my @cn = map { UNIVERSAL::isa($_ ,'IMPL::SQL::Schema::Column') ? $_ ->Name : $_ } @Columns; 173 my @cn = map { UNIVERSAL::isa($_ ,'IMPL::SQL::Schema::Column') ? $_ ->name : $_ } @Columns;
143 exists $this->{$ColumnsByName}->{$_} or die new IMPL::InvalidOperationException('The specified column isn\'t found',$_) foreach @cn; 174 exists $this->{$columnsByName}->{$_} or die new IMPL::InvalidOperationException('The specified column isn\'t found',$_) foreach @cn;
144 175
145 return grep {$_->HasColumn(@cn)} values %{$this->{$Constraints}}; 176 return grep {$_->HasColumn(@cn)} values %{$this->{$constraints}};
146 } 177 }
147 178
148 sub SetPrimaryKey { 179 sub SetPrimaryKey {
149 my ($this,@ColumnList) = @_; 180 my ($this,@ColumnList) = @_;
150 181
151 $this->AddConstraint(new IMPL::SQL::Schema::Constraint::PrimaryKey(Name => $this->{$Name}.'_PK', Table => $this,Columns => \@ColumnList)); 182 $this->AddConstraint(new IMPL::SQL::Schema::Constraint::PrimaryKey(name => $this->{$name}.'_PK', table => $this, columns => \@ColumnList));
152 } 183 }
153 184
154 sub LinkTo { 185 sub LinkTo {
155 my ($this,$table,@ColumnList) = @_; 186 my ($this,$table,@ColumnList) = @_;
156 $table->PrimaryKey or die new IMPL::InvalidOperationException('The referenced table must have a primary key'); 187 $table->primaryKey or die new IMPL::InvalidOperationException('The referenced table must have a primary key');
157 my $constraintName = $this->{$Name}.'_'.$table->Name.'_FK_'.join('_',map {ref $_ ? $_->Name : $_} @ColumnList); 188 my $constraintName = $this->{$name}.'_'.$table->name.'_FK_'.join('_',map {ref $_ ? $_->name : $_} @ColumnList);
158 $this->AddConstraint(new IMPL::SQL::Schema::Constraint::ForeignKey(Name => $constraintName, Table => $this,Columns => \@ColumnList, ReferencedTable => $table, ReferencedColumns => $table->PrimaryKey->Columns)); 189 $this->AddConstraint(new IMPL::SQL::Schema::Constraint::ForeignKey(name => $constraintName, table => $this, columns => \@ColumnList, referencedTable => $table, referencedColumns => $table->primaryKey->columns));
159 } 190 }
160 191
161 sub Dispose { 192 sub Dispose {
162 my ($this) = @_; 193 my ($this) = @_;
163 194
164 $_->Dispose() foreach values %{$this->{$Constraints}}; 195 $_->Dispose() foreach values %{$this->{$constraints}};
165 196
166 undef %{$this}; 197 undef %{$this};
167 $this->SUPER::Dispose(); 198 $this->SUPER::Dispose();
168 } 199 }
169 200
170 1; 201 1;
202
203