# HG changeset patch # User wizard # Date 1301261784 -14400 # Node ID eb3e9861a761261190aff66b14cb24403e132d76 # Parent 6ce1f052b90a3c844f0d5d88777b1c3178704519 SQL traits in progress diff -r 6ce1f052b90a -r eb3e9861a761 Lib/IMPL/Class/Meta.pm --- a/Lib/IMPL/Class/Meta.pm Tue Mar 15 02:32:42 2011 +0300 +++ b/Lib/IMPL/Class/Meta.pm Mon Mar 28 01:36:24 2011 +0400 @@ -69,7 +69,7 @@ $self = ref $self || $self; if ($class ne $self) { - $self->class_data_accessor( $name => $_[0]); + $self->static_accessor( $name => $_[0]); # define own class data } else { $value = $_[0]; } diff -r 6ce1f052b90a -r eb3e9861a761 Lib/IMPL/Object/Abstract.pm --- a/Lib/IMPL/Object/Abstract.pm Tue Mar 15 02:32:42 2011 +0300 +++ b/Lib/IMPL/Object/Abstract.pm Mon Mar 28 01:36:24 2011 +0400 @@ -61,12 +61,6 @@ $self->$_(@_) foreach @{$cacheCTOR{$class} || cache_ctor($class)}; } -sub superCTOR { - my $this = shift; - - warn "The mehod is deprecated, at " . caller; -} - sub toString { my $self = shift; diff -r 6ce1f052b90a -r eb3e9861a761 Lib/IMPL/Object/Fields.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/Object/Fields.pm Mon Mar 28 01:36:24 2011 +0400 @@ -0,0 +1,26 @@ +package IMPL::Object::Fields; +use strict; +use warnings; + +use base qw(IMPL::Object::Abstract); + +sub new { + my $class = shift; + + $class = ref $class || $class; + + my $this = fields::new($class); + $this->callCTOR(@_); + + return $this; +} + +sub surrogate { + my $class = shift; + + $class = ref $class || $class; + + return fields::new($class); +} + +1; \ No newline at end of file diff -r 6ce1f052b90a -r eb3e9861a761 Lib/IMPL/SQL/Schema.pm --- a/Lib/IMPL/SQL/Schema.pm Tue Mar 15 02:32:42 2011 +0300 +++ b/Lib/IMPL/SQL/Schema.pm Mon Mar 28 01:36:24 2011 +0400 @@ -58,6 +58,17 @@ UNIVERSAL::isa($table,'IMPL::SQL::Schema::Table') ? $table : $this->{$Tables}{$table}; } +sub GetTable { + my ($this,$tableName) = @_; + return $this->{$Tables}{$tableName}; +} + +sub RenameTable { + my ($this,$oldName,$newName) = @_; + + +} + sub Dispose { my ($this) = @_; diff -r 6ce1f052b90a -r eb3e9861a761 Lib/IMPL/SQL/Schema/Traits.pm --- a/Lib/IMPL/SQL/Schema/Traits.pm Tue Mar 15 02:32:42 2011 +0300 +++ b/Lib/IMPL/SQL/Schema/Traits.pm Mon Mar 28 01:36:24 2011 +0400 @@ -3,56 +3,369 @@ use IMPL::_core::version; use IMPL::Exception(); -use base qw(IMPL::Object IMPL::Object::Autofill); +use IMPL::base qw(IMPL::Object); -# this is a base class for all table traits +################################################### + package IMPL::SQL::Traits::Table; +use IMPL::base qw(IMPL::Object::Fields); -our @ISA = qw(IMPL::SQL::Traits); +use fields qw( + name + columns + constraints + options +); + +sub CTOR { + my ($this,$table,$columns,$constraints,$options) = @_; + + $this->{name} = $table; + $this->{columns} = $columns; + $this->{constraints} = $constraints; + $this->{options} = $options; +} + +################################################### + +package IMPL::SQL::Traits::Column; +use IMPL::base qw(IMPL::Object::Fields); + +use fields qw( + name + type + isNullable + defaultValue + tag +); + +sub CTOR { + my ($this, $name, $type, %args) = @_; + + $this->{name} = $name or die new IMPL::InvalidArgumentException("name"); + $this->{type} = $type or die new IMPL::InvalidArgumentException("type"); + $this->{isNullable} = $args{isNullable} if exists $args{isNullable}; + $this->{defaultValue} = $args{defaultValue} if exists $args{defaultValue}; + $this->{tag} = $args{tag} if exists $args{tag}; +} + +################################################## + +package IMPL::SQL::Traits::Constraint; +use IMPL::base qw(IMPL::Object::Fields); + +use fields qw( + name + tableName + columns +); + +sub CTOR { + my ($this, $name, $tableName, $columns) = @_; + + $this->{name} = $name; + $this->{tableName} = $tableName; + $$this->{columns} = $columns; +} + +################################################## + +package IMPL::SQL::Traits::PrimaryKey; + +use IMPL::base qw(IMPL::SQL::Traits::Constraint); + +__PACKAGE__->PassThroughArgs; + +################################################## + +package IMPL::SQL::Traits::Index; + +use IMPL::base qw(IMPL::SQL::Traits::Constraint); + +__PACKAGE__->PassThroughArgs; + +################################################## + +package IMPL::SQL::Traits::Unique; + +use IMPL::base qw(IMPL::SQL::Traits::Constraint); + +__PACKAGE__->PassThroughArgs; +################################################## + +package IMPL::SQL::Traits::ForeignKey; + +use IMPL::base qw(IMPL::SQL::Traits::Constraint); +use fields qw( + foreignTable + foreignColumns +); + +our %CTOR = ( + 'IMPL::SQL::Traits::Constraint' => sub { @_[0..2] } +); + +sub CTOR { + my ($this,$foreignTable,$foreignColumns) = @_[0,4,5]; + + $this->{foreignTable} = $foreignTable; + $this->{foreignColunms} = $foreignColumns; +} + + +################################################## + +package IMPL::SQL::Traits::CreateTable; + +use IMPL::base qw(IMPL::SQL::Traits); +use IMPL::Class::Property; +use IMPL::lang; + +BEGIN { + public property table => prop_get | owner_set; +} + +sub CTOR { + my ($this,$table) = @_; + + die new IMPL::InvalidArgumentException("table", "An object of IMPL::SQL::Traits::Table type is required") + unless is $table, typeof IMPL::SQL::Traits::Table; + + $this->table($table); +} + +sub apply { + my ($this,$schema) = @_; + + return 0 if ( $schema->GetTable( $this->table->{name} ) ); + + $schema->AddTable($this->table); + return 1; +} + +################################################## + +package IMPL::SQL::Traits::DropTable; +use IMPL::base qw(IMPL::SQL::Traits); +use IMPL::Class::Property; + +BEGIN { + public property tableName => prop_get | owner_set; +} + +sub CTOR { + my ($this,$tableName) = @_; + + $this->tableName($tableName) or die new IMPL::InvalidArgumentException("tableName is required"); +} + +sub apply { + my ($this,$schema) = @_; + + return 0 if $schema->GetTable( $this->tableName ); + + $schema->RemoveTable($this->tableName); + + return 1; +} + +################################################## + +package IMPL::SQL::Traits::RenameTable; +use IMPL::base qw(IMPL::SQL::Traits); use IMPL::Class::Property; BEGIN { - public property tableName => prop_all; + public property tableName => prop_get | owner_set; + public property tableNewName => prop_get | owner_set; +} + +sub CTOR { + my ($this, $oldName, $newName) = @_; + + $this->tableName($oldName) or die new IMPL::InvalidArgumentException("A table name is required"); + $this->tableNewName($newName) or die new IMPL::InvalidArgumentException("A new table name is required"); +} + +sub apply { + my ($this,$schema) = @_; + + return 0 if not $schema->GetTable($this->tableName) or $schema->GetTable($this->tableNewName); + + $this->RenameTable($this->tableName, $this->tableNewName); + + return 1; +} + +################################################# + +package IMPL::SQL::Traits::AlterTableAddColumn; +use IMPL::base qw(IMPL::SQL::Traits); +use IMPL::Class::Property; +use IMPL::lang; + +BEGIN { + public property tableName => prop_get | owner_set; + public property column => prop_get | owner_set; } -sub verify { - my ($this, $schema) = @_; +sub CTOR { + my ($this,$tableName,$column) = @_; + + $this->tableName($tableName) or die new IMPL::InvalidArgumentException("A table name is required"); + + die new IMPL::InvalidArgumentException("A column should be a IMPL::SQL::Traits::Column object") + unless is $column, typeof IMPL::SQL::Traits::Column; + + $this->column($column); +} + +sub apply { + my ($this,$schema) = @_; + + my $table = $schema->GetTable($this->tableName) or return 0; + + return 0 if $table->GetColumn( $this->column->{name} ); + + $table->AddColumn($this->column); + + return 1; +} + +################################################# + +package IMPL::SQL::Traits::AlterTableDropColumn; +use IMPL::base qw(IMPL::SQL::Traits); +use IMPL::Class::Property; + +BEGIN { + public property tableName => prop_get | owner_set; + public property columnName => prop_get | owner_set; +} + +sub CTOR { + my ($this,$table,$column) = @_; + + $this->tableName($table) or die new IMPL::InvalidArgumentException(tableName => "A table name should be specified"); + $this->columnName($column) or die new IMPL::InvalidArgumentException(columnName => "A column name should be specified"); +} + +sub apply { + my ($this,$schema) = @_; + + local $@; + + return eval { + $schema->GetTable($this->tableName)->RemoveColumn($this->columnName); + return 1; + } || 0; } -package IMPL::SQL::Traits::Table::Create; +################################################# -our @ISA = qw(IMPL::SQL::Traits::Table); +package IMPL::SQL::Traits::AlterTableChangeColumn; +use IMPL::base qw(IMPL::SQL::Traits); +use IMPL::Class::Property; -package IMPL::SQL::Traits::Table::Drop; - -our @ISA = qw(IMPL::SQL::Traits::Table); +BEGIN { + public property tableName => prop_get | owner_set; + public property columnName => prop_get | owner_set; + public property columnType => prop_get | owner_set; + public property defaultValue => prop_get | owner_set; + public property isNullable => prop_get | owner_set; + public property options => prop_get | owner_set; +} -package IMPL::SQL::Traits::Table::AlterAttributes; - -our @ISA = qw(IMPL::SQL::Traits::Table); +sub CTOR { + my ($this, $table,$column,%args) = @_; + + $this->tableName($table) or die new IMPL::InvalidArgumentException(tableName => "A table name is required"); + $this->columnName($column) or die new IMPL::InvalidArgumentException(columnName => "A column name is required"); + + $this->$_($args{$_}) + for (grep exists $args{$_}, qw(columnType defaultValue isNullable options)); +} -package IMPL::SQL::Traits::Table::AlterName; +sub apply { + my ($this,$schema) = @_; + + local $@; + + return eval { + my $column = $schema->GetTable($this->tableName)->GetColumn($this->columnName); + $column->SetType($this->columnType) if $this->columnType; + $column->SetNullable($this->isNullable) if $this->isNullable; + $column->SetDefaultValue($this->defaultValue) if $this->defaultValue; + $column->SetOptions($this->options) if $this->options; + + return 1; + } || 0; +} -our @ISA = qw(IMPL::SQL::Traits::Table); +################################################# +package IMPL::SQL::Traits::AlterTableAddConstraint; +use IMPL::base qw(IMPL::SQL::Traits); +use IMPL::Class::Property; +use IMPL::lang; - -package IMPL::SQL::Traits::Column; +BEGIN { + public property tableName => prop_get | owner_set; + public property constraint => prop_get | owner_set; +} -our @ISA = qw(SQL::IMPL::Traits); +sub CTOR { + my ($this,$table,$constraint) = @_; + + $this->tableName($table) or die new IMPL::InvalidArgumentException( tableName => "A table name is required"); + + die new IMPL::InvalidArgumentException(constaraint => "A valid IMPL::SQL::Traits::Constarint is required") + unless is $constraint, typeof IMPL::SQL::Traits::Constraint; + + $this->constraint($constraint); +} -package IMPL::SQL::Traits::Column::Create; +sub apply { + my ($this,$schema) = @_; + + local $@; + + return eval { + $schema->GetTable($this->tableName)->AddConstraint($this->constraint); + return 1; + } || 0; + +} -our @ISA = qw(IMPL::SQL::Traits::Column); +################################################# -package IMPL::SQL::Traits::Column::Drop; +package IMPL::SQL::Traits::AlterTableDropConstraint; +use IMPL::base qw(IMPL::SQL::Traits); +use IMPL::Class::Property; + +BEGIN { + public property tableName => prop_get | owner_set; + public property constraintName => prop_get | owner_set; +} -our @ISA = qw(IMPL::SQL::Traits::Column); +sub CTOR { + my ($this,$table,$constraint) = @_; + + die new IMPL::InvalidArgumentException( tableName => "A table name is required" ) unless $table; + die new IMPL::InvalidArgumentException( constraintName => "A constraint name is required" ) unless $constraint; +} -package IMPL::SQL::Traits::Column::Alter; - -our @ISA = qw(IMPL::SQL::Traits::Column); +sub apply { + my ($this,$schema) = @_; + + my $table = $schema->GetTable($this->tableName) or return 0; + + return 0 unless $table->GetConstraint($this->constraintName); + + $table->RemoveConstraint($this->constraintName); + return 1; +} 1; @@ -68,6 +381,195 @@ =head1 DESCRIPTION Изменения схемы могу быть представлены в виде последовательности примитивных операций. +Правила выполнения последовательности примитывных действий могут варьироваться +в зависимости от процессора, который их выполняет. Например C. +Данные, которые содержаться в примитивных операциях не могут существовать независимо от схемы. + +=head1 OPEARATIONS + +=head2 General + +Методы обще для всех примитивных операций. + +=over + +=item C + +Пытается приминить операцию к указанной схеме. + +Возвращаемое значение: + +=over + +=item C + +Операция успешно применена к схеме. + +=item C + +Операция не может быть применена к схеме. + +=back + +=back + +=head2 Primitive operations + +=over + +=item C + +Создает таблицу + +=over + +=item C + +=item C<[get]table> + +C - описание создаваемой таблицы + +=back + +=item C + +Удалает таблицу по имени + +=over + +=item C + +=item C<[get]tableName> + +Имя удаляемой таблицы + +=back + +=item C + +=over + +=item C + +=item C<[get]tableName> + +Имя таблицы, которую требуется переименовать + +=item C<[get]tableNewName> + +Новое имя таблицы + +=back + +=item C + +Добавляет столбец в таблицу + +=over + +=item C + +=item C<[get]tableName> + +Имя таблицы в которую нужно добавить столбец + +=item C<[get]column> + +C - описание столбца который нужно добавить + +=back + +=item C + +Удаляет столбец из таблицы + +=over + +=item C + +=item C<[get]tableName> + +Имя таблицы в которой нужно удалить столбец + +=item C<[get]columnName> + +Имя столбца для удаления + +=back + +=item C + +Меняет описание столбца + +=over + +=item C + +C<%args> - хеш, ключами которого являются оставшиеся свойства создаваемого объекта. + +=item C<[get]tableName> + +Имя таблицы в которой находится столбец. + +=item C<[get]columnName> + +Имя столбца для изменения + +=item C<[get]columnType> + +Новый тип столбца. Не задан, если тип не меняется + +=item C<[get]defaultValue> + +Значение по умолчанию. Не задано, если не меняется + +=item C<[get]isNullable> + +Может ли столбец содержать C. Не задано, если не меняется. + +=item C<[get]options> + +Хеш опций, не задан, если опции не меняются + +=back + +=item C + +Базовый класс для операций по добавлению ограничений + +=over + +=item C + +=item C<[get]tableName> + +Имя таблицы в которую добавляется ограничение. + +=item C<[get]constraint> + +C - описние ограничения, которое нужно добавить. + +=back + +=item C + +Удаляет ограничение на таблицу + +=over + +=item C + +=item C<[get]tableName> + +Имя таблицы в которой требуется удалить ограничение. + +=item C<[get]constraintName> + +Имя ограничения для удаления. + +=back + +=back =cut \ No newline at end of file diff -r 6ce1f052b90a -r eb3e9861a761 Lib/IMPL/lang.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/lang.pm Mon Mar 28 01:36:24 2011 +0400 @@ -0,0 +1,15 @@ +package IMPL::lang; +use strict; +use warnings; + +use IMPL::base qw(Exporter); +use IMPL::_core::version; + + +our @EXPORT = qw(&is); + +sub is($$) { + eval { $_[0]->isa($_[1]) } +} + +1; \ No newline at end of file diff -r 6ce1f052b90a -r eb3e9861a761 _test/Test/Object/Fields.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/_test/Test/Object/Fields.pm Mon Mar 28 01:36:24 2011 +0400 @@ -0,0 +1,54 @@ +package Test::Object::Fields; +use strict; +use warnings; + +use base qw( IMPL::Test::Unit ); +use IMPL::Test qw(test failed cmparray); + +__PACKAGE__->PassThroughArgs; + +{ + package Fields::Foo; + use base qw(IMPL::Object::Fields); + + use fields qw(name info); + + sub CTOR { + my ($this,$name,$info) = @_; + + $this->{name} = $name; + $this->{info} = $info; + } + + package Fields::Bar; + use base qw(Fields::Foo); + use fields qw(id); + + our %CTOR = ( + 'Fields::Foo' => sub { + my %args = @_; + Bar => $args{info}; + } + ); + + sub CTOR { + my ($this,%args) = @_; + + $this->{id} = $args{id}; + } +} + +test constructObject => sub { + my $obj = new Fields::Foo( Peter => '34-fg-78' ); + + $obj->{name} eq 'Peter' or failed "A value of 'name' field is wrong","Expected: 'Peter'","Got: '$obj->{name}'"; +}; + +test inheritance => sub { + my $obj = new Fields::Bar( id => '1ba356f', info => 'standard bar'); + + $obj->{name} eq 'Bar' or failed "A value of 'name' property is wrong","Expected: 'Bar'","Got: '$obj->{name}'"; + $obj->{id} eq '1ba356f' or failed "A value of 'id' property is wrong","Expected: '1ba356f'","Got: '$obj->{id}'"; +}; + +1; \ No newline at end of file diff -r 6ce1f052b90a -r eb3e9861a761 _test/object.t --- a/_test/object.t Tue Mar 15 02:32:42 2011 +0300 +++ b/_test/object.t Mon Mar 28 01:36:24 2011 +0400 @@ -10,6 +10,7 @@ Test::Class::Meta Test::Object::Common Test::Object::List + Test::Object::Fields ); $plan->AddListener(new IMPL::Test::TAPListener);