# HG changeset patch # User Sergey # Date 1255911234 -14400 # Node ID 6d33f75c6e1f2a899c2a8896f4503c56cdf23f57 # Parent b544a772b654def9d14b32d5fa105e9527730b47 ORM in works diff -r b544a772b654 -r 6d33f75c6e1f Lib/IMPL/ORM/Entity.pm --- a/Lib/IMPL/ORM/Entity.pm Fri Oct 16 16:37:53 2009 +0400 +++ b/Lib/IMPL/ORM/Entity.pm Mon Oct 19 04:13:54 2009 +0400 @@ -16,7 +16,13 @@ sub CTOR { my ($this,$class,$schema) = @_; - + $this->{$Class} = $class; + (my $name = $class) =~ s/::/_/g; + $this->{$Name} = $name; + $this->Schema = $schema; + $this->{$Values} = { + map {$_->{name},{type => $_->{type}, virtual => $_->{virtual}}} @$schema + }; } sub Store; @@ -26,19 +32,17 @@ my ($this,$prop,$value) = @_; if ( my $container = $this->{$Values}{$prop} ) { - if ($container->{type} eq 'SCALAR') { - - } else { - - } - + $container->{oldValue} = $container->{value}; + $container->{value} = $value; } else { die new IMPL::InvalidOperationException("Property not found",$this->Name,$prop); } } sub Get { + my ($this,$prop) = @_; + return $this->{$Values}{$prop}{value}; } 1; diff -r b544a772b654 -r 6d33f75c6e1f Lib/IMPL/ORM/Helpers.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/ORM/Helpers.pm Mon Oct 19 04:13:54 2009 +0400 @@ -0,0 +1,24 @@ +package IMPL::ORM::Helpers; +use strict; +use warnings; + +require Exporter; +our @ISA = qw(Exporter); +our @EXPORT_OK = qw(&Map &Box); + +sub Map($$) { + my ($TKey,$TValue) = @_; + + $TKey =~ s/:://g; + $TValue =~ s/:://g; + + return "IMPL::ORM::Map::${TKey}${TValue}"; +} + +sub Box($) { + my ($TValue) = @_; + $TValue =~ s/:://g; + return "IMPL::ORM::Box::$TValue"; +} + +1; diff -r b544a772b654 -r 6d33f75c6e1f Lib/IMPL/ORM/Object.pm --- a/Lib/IMPL/ORM/Object.pm Fri Oct 16 16:37:53 2009 +0400 +++ b/Lib/IMPL/ORM/Object.pm Mon Oct 19 04:13:54 2009 +0400 @@ -7,9 +7,15 @@ use IMPL::Class::Property::Direct; require IMPL::ORM::Entity; +require IMPL::ORM::Schema::Entity; +require IMPL::ORM::Schema::Field; +require IMPL::ORM::Schema::Relation::HasMany; +require IMPL::ORM::Schema::Relation::HasOne; +require IMPL::ORM::Schema::Relation::Subclass; BEGIN { private _direct property _entities => prop_all; + public property objectType => prop_all; } my %schemaCache; @@ -36,18 +42,19 @@ return $this->{$_entities}{$class} ? $this->{$_entities}{$class}->Get($prop,$value) : undef; } -sub _PropertyImplementor { - 'IMPL::ORM::Property' +#sub _PropertyImplementor { +# 'IMPL::ORM::Property' +#} + +sub entityName { + (my $self = ref $_[0] || $_[0]) =~ s/::/_/g; + return $self; } sub ormGetSchema { - my ($self) = @_; - - my $class = ref $self || $self; + my ($self,$dataSchema) = @_; - return $schemaCache{$class} if $schemaCache{$class}; - - my %schema; + my $schema = IMPL::ORM::Schema::Entity->new($self->entityName); foreach my $ormProp ( $self->get_meta( @@ -55,17 +62,22 @@ sub { UNIVERSAL::isa($_->Implementor, 'IMPL::ORM::Property' ) }, - 1 + 0 ) ){ - push @{$schema{$ormProp->Class}},{ - name => $ormProp->Name, - virtual => $ormProp->Virtual, - type => $ormProp->Type - }; + if ($ormProp->Mutators & prop_list) { + my $type = $dataSchema->resolveType($ormProp->Type) or die new IMPL::InvalidOperationException("Failed to resolve a reference type due building schema for a class", $ormProp->Class, $ormProp->Name); + $schema->appendChild( new IMPL::ORM::Schema::Relation::HasMany($ormProp->Name, $type->entityName) ); + } elsif (my $type = $dataSchema->isValueType($ormProp->Type,'IMPL::ORM::Object')) { + $schema->appendChild( new IMPL::ORM::Schema::Field($ormProp->Name,$type) ); + } elsif (my $entity = $dataSchema->resolveType($ormProp->Type)) { + $schema->appendChild( new IMPL::ORM::Schema::Relation::HasOne($ormProp->Name,$entity->entityName)); + } else { + die new IMPL::Exception('Uexpected error due building schema for a class', $ormProp->Class, $ormProp->Name); + } } - return ($schemaCache{$class} = \%schema); + return $schema; } 1; @@ -79,4 +91,7 @@ Базовый объект для реляционного отображения, содержит в себе реляционные записи представляющие данный объект. +Каждый класс отображается в определенную сущность. Сущности хранят +состояние объектов в том виде в котором удобно записывать в реляционную базу. + =cut \ No newline at end of file diff -r b544a772b654 -r 6d33f75c6e1f Lib/IMPL/ORM/Schema.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/ORM/Schema.pm Mon Oct 19 04:13:54 2009 +0400 @@ -0,0 +1,64 @@ +package IMPL::ORM::Schema; +use strict; +use warnings; + +use base qw(IMPL::DOM::Document); +use IMPL::Class::Property; + +BEGIN { + public property mapValueTypes => prop_get | owner_set; + public property mapReferenceTypes => prop_get | owner_set; +} + +sub CTOR { + my ($this ) = @_; + $this->mapValueTypes({}); + $this->mapReferenceTypes({}); +} + +# return an entity for the specified typename +# makes forward declaration if nesessary +sub resolveType { + my ($this,$typeName) = @_; + + $this = ref $this ? $this : $this->instance; + + if (my $entity = $this->mapReferenceTypes->{$typeName}) { + return $entity; + } elsif (UNIVERSAL::isa($typeName,'IMPL::ORM::Object')) { + return $this->declareReferenceType($typeName); + } else { + return undef; + } +} + +# returns valuetype name +sub isValueType { + my ($this,$typeName) = @_; + + $this = ref $this ? $this : $this->instance; + + return $this->mapValueTypes->{$typeName}; +} + +my %instances; +sub instance { + my ($class) = @_; + + return ($instances{$class} || ($instances{$class} = $class->new)); +} + +1; + +__END__ + +=pod + +=head1 DESCRIPTION + +Схема данных, представляет собой DOM документ, элементами которой +являются сущности. + +Каждый узел - это описание сущности. + +=cut \ No newline at end of file diff -r b544a772b654 -r 6d33f75c6e1f Lib/IMPL/ORM/Schema/Entity.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/ORM/Schema/Entity.pm Mon Oct 19 04:13:54 2009 +0400 @@ -0,0 +1,24 @@ +package IMPL::ORM::Schema::Entity; +use strict; +use warnings; + +use base qw(IMPL::DOM::Node); +use IMPL::Class::Property; + +BEGIN { + public property entityName => prop_get | owner_set; +} + +our %CTOR = ( + 'IMPL::DOM::Node' => sub { + nodeName => 'Entity' + } +); + +sub CTOR { + my ($this,$name) = @_; + + $this->entityName($name); +} + +1; diff -r b544a772b654 -r 6d33f75c6e1f Lib/IMPL/ORM/Schema/Field.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/ORM/Schema/Field.pm Mon Oct 19 04:13:54 2009 +0400 @@ -0,0 +1,28 @@ +package IMPL::ORM::Schema::Field; +use strict; +use warnings; + +use base qw(IMPL::DOM::Node); +use IMPL::Class::Property; + +BEGIN { + public property fieldName => prop_get | owner_set; + public property fieldType => prop_get | owner_set; +} + +our %CTOR = ( + 'IMPL::DOM::Node' => sub { nodeName => 'Field' } +); + +sub CTOR { + my ($this,$name,$type) = @_; + + $this->fieldName($name) or die new IMPL::InvalidArgumentException('A name is required for the field'); + $this->fieldType($type) or die new IMPL::InvalidArgumentException('A type is required for the field'); +} + +sub canHaveChildren { + 0; +} + +1; diff -r b544a772b654 -r 6d33f75c6e1f Lib/IMPL/ORM/Schema/Relation.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/ORM/Schema/Relation.pm Mon Oct 19 04:13:54 2009 +0400 @@ -0,0 +1,12 @@ +package IMPL::ORM::Schema::Relation; +use strict; +use warnings; + +use base qw(IMPL::DOM::Node); + +our %CTOR =( + 'IMPL::DOM::Node' => sub { nodeName => $_[0] } +); + + +1; diff -r b544a772b654 -r 6d33f75c6e1f Lib/IMPL/ORM/Schema/Relation/HasMany.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/ORM/Schema/Relation/HasMany.pm Mon Oct 19 04:13:54 2009 +0400 @@ -0,0 +1,27 @@ +package IMPL::ORM::Schema::Relation::HasMany; +use strict; +use warnings; + +use base qw(IMPL::ORM::Schema::Relation); +use IMPL::Class::Property; + +BEGIN { + public property target => prop_get | owner_set; + public property name => prop_get | owner_set; +} + +our %CTOR = ( + 'IMPL::ORM::Schema::Relation' => sub { 'HasMany' } +); + +sub CTOR { + my ($this,$name,$target) = @_; + $this->name($name) or die new IMPL::InvalidArgumentException('A name is required for this relation'); + $this->target($target) or die new IMPL::InvalidArgumentException('A target is required for this relation',$name); +} + +sub canHaveChildren { + 0; +} + +1; diff -r b544a772b654 -r 6d33f75c6e1f Lib/IMPL/ORM/Schema/Relation/HasOne.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/ORM/Schema/Relation/HasOne.pm Mon Oct 19 04:13:54 2009 +0400 @@ -0,0 +1,28 @@ +package IMPL::ORM::Schema::Relation::HasOne; +use strict; +use warnings; + +use base qw(IMPL::ORM::Schema::Relation); +use IMPL::Class::Property; + +BEGIN { + public property target => prop_get | owner_set; + public property name => prop_get | owner_set; +} + +our %CTOR = ( + 'IMPL::ORM::Schema::Relation' => sub { 'HasOne' } +); + +sub CTOR { + my ($this,$name,$target) = @_; + $this->name($name) or die new IMPL::InvalidArgumentException('A name is required for this relation'); + $this->target($target) or die new IMPL::InvalidArgumentException('A target is required for this relation',$name); +} + +sub canHaveChildren { + 0; +} + + +1; diff -r b544a772b654 -r 6d33f75c6e1f Lib/IMPL/ORM/Schema/Relation/Subclass.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/ORM/Schema/Relation/Subclass.pm Mon Oct 19 04:13:54 2009 +0400 @@ -0,0 +1,26 @@ +package IMPL::ORM::Schema::Relation::Subclass; +use strict; +use warnings; + +use base qw(IMPL::ORM::Schema::Relation); +use IMPL::Class::Property; + +BEGIN { + public property base => prop_get | owner_set; +} + +our %CTOR = ( + 'IMPL::DOM::Node' => sub { 'Subclass' } +); + +sub CTOR { + my ($this,$base) = @_; + + $this->base($base) or die new IMPL::InvalidArgumentException('A base is required for this relation'); +} + +sub canHaveChildren { + 0; +} + +1; diff -r b544a772b654 -r 6d33f75c6e1f _test/Test/DOM/Schema.pm --- a/_test/Test/DOM/Schema.pm Fri Oct 16 16:37:53 2009 +0400 +++ b/_test/Test/DOM/Schema.pm Mon Oct 19 04:13:54 2009 +0400 @@ -20,7 +20,7 @@ test AutoverifyMetaSchema => sub { my $metaSchema = IMPL::DOM::Schema->MetaSchema(); - + if (my @errors = $metaSchema->Validate($metaSchema)) { failed "Self verification failed", map $_ ? $_->Message : 'unknown', @errors; } diff -r b544a772b654 -r 6d33f75c6e1f _test/Test/ORM/Schema.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/_test/Test/ORM/Schema.pm Mon Oct 19 04:13:54 2009 +0400 @@ -0,0 +1,57 @@ +package Test::ORM::Schema; +use strict; +use warnings; + +require Exporter; +our @ISA = qw(Exporter); +our @EXPORT_OK = qw(); + +package Test::ORM::Schema::Data::User; +use base qw(IMPL::ORM::Object); +use IMPL::Class::Property; + +BEGIN { + public property Name => prop_all, { type => 'String' }; # Field + public property Id => prop_all, { type => 'String' }; # Field + public property Roles => prop_all | prop_list, { type=> 'Test::ORM::Schema::Data::Role'}; # HasMany +} + +package Test::ORM::Schema::Data::Role; +use base qw(IMPL::ORM::Object); +use IMPL::Class::Property; + +BEGIN { + public property Name => prop_all, { type => 'String' }; # Field +} + +package Test::ORM::Schema::Data::Session; +use base qw(IMPL::ORM::Object); +use IMPL::Class::Property; +use IMPL::ORM::Helpers qw(Map); + +BEGIN { + public property Id => prop_get, { type => 'String' }; # Field + public property User => prop_get, { type => 'Test::ORM::Schema::Data::User' }; # HasOne + public property Data => prop_all, { type => Map( 'String','String' ) }; # HasOne + public property AccessTime => prop_get { type => 'DateTime' }; # Field +} + +package Test::ORM::Schema::Data; +use base qw(IMPL::ORM::Schema); + +__PACKAGE__->usePrefix(__PACKAGE__); +__PACKAGE__->Classes qw( + User + Role + Session +); + +__PACKAGE__->ValueTypes ( + 'String' => 'IMPL::ORM::Value::String', + 'DateTime' => 'IMPL::ORM::Value::DateTime', + 'Integer' => 'IMPL::ORM::Value::Inetger', + 'Float' => 'IMPL::ORM::Value::Float', + 'Decimal' => 'IMPL::ORM::Value::Decimal' +); + +1; diff -r b544a772b654 -r 6d33f75c6e1f impl.kpf --- a/impl.kpf Fri Oct 16 16:37:53 2009 +0400 +++ b/impl.kpf Mon Oct 19 04:13:54 2009 +0400 @@ -456,6 +456,32 @@ default + + + + + + 9011 + + + _test/Test/ORM/Schema.pm + + Perl + + + + application/x-www-form-urlencoded + GET + 1 + 0 + 0 + + + enabled + + + default +