diff Lib/Schema/DataSource.pm @ 0:03e58a454b20

Создан репозитарий
author Sergey
date Tue, 14 Jul 2009 12:54:37 +0400
parents
children 16ada169ca75
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Lib/Schema/DataSource.pm	Tue Jul 14 12:54:37 2009 +0400
@@ -0,0 +1,138 @@
+package Configuration;
+our $DataDir;
+package Schema::DataSource;
+use Common;
+use strict;
+use base qw(Object);
+
+use BNFCompiler;
+use Schema::DB;
+use Schema;
+use URI::file;
+
+BEGIN {
+    DeclareProperty ProcessedSchemas => ACCESS_NONE;  #{ uri => schema }
+    DeclareProperty Types => ACCESS_READ; # Schema
+    DeclareProperty DataSourceBuilder => ACCESS_READ;
+    DeclareProperty Compiler => ACCESS_NONE;
+}
+
+sub CTOR {
+    my ($this,%args) = @_;
+    
+    $this->{$DataSourceBuilder} = $args{'DataSourceBuilder'} or die new Exception('A data source builder is required');
+    $this->{$Types} = new Schema;
+    $this->{$Compiler} = new BNFCompiler(SchemaCache => "${DataDir}Cache/",Transform => sub { BNFCompiler::DOM::TransformDOMToHash(@_,{skip_spaces => 1})} );
+    $this->{$Compiler}->LoadBNFSchema(file => 'Schema/schema.def');
+}
+
+sub as_list {
+    return( map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : defined $_ ? $_ : () } @_ );
+}
+
+sub ProcessSchema {
+    my ($this,$uriFile) = @_;
+    
+    return 1 if $this->{$ProcessedSchemas}{$uriFile->as_string};
+    
+    my $uriDir = URI::file->new('./')->abs($uriFile);
+    $this->{$ProcessedSchemas}->{$uriFile->as_string} = 1;
+    
+    my $Schema = $this->ParseSchema($uriFile);
+    
+    foreach my $item (as_list($Schema->{'header'}{'include_item'})) {
+        my $uriItem = URI::file->new($item->{'file_name'})->abs($uriDir);
+        $this->ProcessSchema($uriItem);
+    }
+    
+    $this->ConstructTypes($Schema);
+    
+}
+
+sub ParseSchema {
+    my ($this,$fileUri) = @_;
+    
+    my $fileName = $fileUri->file;
+    open my $hfile,"$fileName" or die new Exception('Failed to read the file',$fileName,$!);
+    local $/ = undef;
+    my $Schema = $this->{$Compiler}->Parse(<$hfile>);
+
+    return $Schema;
+}
+
+sub ConstructTypes {
+    my ($this,$schema) = @_;
+    return if not $schema->{'class'};
+    
+    foreach my $class (as_list($schema->{'class'})){
+        # îáúÿâëåíèå òèïà
+        my $type;
+        my $builder;
+        if ($class->{'type_definition'}{'args_list'}) {
+            $type = $this->{$Types}->CreateTemplate($class->{'type_definition'}{'name'},as_list($class->{'type_definition'}{'args_list'}{'name'}));
+        } else {
+            $type = $this->{$Types}->CreateType($class->{'type_definition'}{'name'});
+        }
+        
+        $type->SetAttributes(ValueType => 1) if $class->{'value_type'};
+        
+        my $mappingTip = $this->{$DataSourceBuilder}->GetClassMapping($type);
+        
+        
+        # îáðàáàòûâàåì ñïèñîê áàçîâûõ êëàññîâ
+        
+        if ($class->{'base_types'}) {
+            foreach my $typename (as_list($class->{'base_types'}{'type'})) {
+                $type->AddBase(MakeTypeName($typename));
+            }
+        }
+        
+        # îáðàáàòûâàåì ñïèñîê ñâîéñòâ
+        if ($class->{'property_list'}) {
+            foreach my $property (as_list($class->{'property_list'}{'property'})) {
+                $type->InsertProperty($property->{'name'},MakeTypeName($property->{'type'}));
+                if (my $mapping = $property->{'mapping'}) {
+                    $mappingTip->PropertyMapping($property->{'name'},Column => $mapping->{'column_name'},DBType => $mapping->{'db_type'});
+                }
+            }
+        }
+    }
+}
+
+sub MakeTypeName {
+    my ($typename) = @_;
+    
+    return new Schema::TypeName(
+        $typename->{'name'},
+        (
+            $typename->{'template_list'} ?
+                map { MakeTypeName($_) } as_list($typename->{'template_list'}{'type'})
+            :
+                ()
+        )
+    );
+}
+
+sub BuildSchema {
+    my ($this,$fileName) = @_;
+    
+    my $uriFile = URI::file->new_abs($fileName);
+    
+    $this->ProcessSchema($uriFile);
+    
+    $this->{$Types}->Close();
+
+    foreach my $type ($this->{$Types}->EnumTypes(skip_templates => 1)) {
+        $this->{$DataSourceBuilder}->AddType($type);
+    }
+}
+
+sub DESTROY {
+    my ($this) = @_;
+    
+    $this->{$Compiler}->Dispose;
+    $this->{$DataSourceBuilder}->Dispose;
+    $this->{$Types}->Dispose;
+}
+
+1;