Mercurial > pub > Impl
comparison Lib/Deployment/Batch/CDBIUpdate.pm @ 0:03e58a454b20
Создан репозитарий
| author | Sergey |
|---|---|
| date | Tue, 14 Jul 2009 12:54:37 +0400 |
| parents | |
| children | 16ada169ca75 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:03e58a454b20 |
|---|---|
| 1 use strict; | |
| 2 package Deployment::Batch::CDBIUpdate; | |
| 3 use Common; | |
| 4 use base qw(Deployment::Batch::Generic); | |
| 5 | |
| 6 use DBI; | |
| 7 use Schema::DataSource; | |
| 8 use Schema::DataSource::CDBIBuilder; | |
| 9 | |
| 10 | |
| 11 BEGIN { | |
| 12 DeclareProperty DataSchemaFile => ACCESS_READ; | |
| 13 DeclareProperty DataSourceDir => ACCESS_READ; | |
| 14 DeclareProperty DSNamespace => ACCESS_READ; | |
| 15 DeclareProperty DBConnection => ACCESS_READ; | |
| 16 DeclareProperty DBTraitsClass => ACCESS_READ; | |
| 17 DeclareProperty SchemaPrev => ACCESS_READ; | |
| 18 } | |
| 19 | |
| 20 sub CTOR { | |
| 21 my ($this,%args) = @_; | |
| 22 | |
| 23 $this->{$DataSchemaFile} = $args{'Source'} or die new Exception('A data shema file is required'); | |
| 24 $this->{$DataSourceDir} = $args{'Output'} or die new Exception('A directory for a data source is required'); | |
| 25 $this->{$DSNamespace} = $args{'Namespace'} || 'DataSource'; | |
| 26 $this->{$DBTraitsClass} = $args{'DBTraits'} or die new Exception('A DBTraitsClass is required'); | |
| 27 | |
| 28 (my $modname = $args{'DBTraits'}.'.pm') =~ s/::/\//g; | |
| 29 $this->Log("Loading DBTraits '$modname'"); | |
| 30 require $modname; | |
| 31 } | |
| 32 | |
| 33 sub Run { | |
| 34 my ($this) = @_; | |
| 35 | |
| 36 $this->{$DBConnection} = $this->Context->{Connection}; | |
| 37 | |
| 38 my $prefix = $this->{$DSNamespace}.'::'; | |
| 39 | |
| 40 my $schemaDS = new Schema::DataSource(DataSourceBuilder => new Schema::DataSource::CDBIBuilder); | |
| 41 $schemaDS->BuildSchema($this->{$DataSchemaFile}); | |
| 42 | |
| 43 my $schemaDB = $schemaDS->DataSourceBuilder->BuildDBSchema(); | |
| 44 (my $fname = $this->{$DataSourceDir}.$this->{$DSNamespace}.'.pm') =~ s/::/\//g; | |
| 45 | |
| 46 # we are in the immediate mode, so the file will be backupped immediatelly; | |
| 47 $this->Log("Backup $fname"); | |
| 48 Deployment::Batch->Backup( File => $fname ); | |
| 49 | |
| 50 $this->Log("Write the datasource '$this->{$DSNamespace}' to '$this->{$DataSourceDir}'"); | |
| 51 $schemaDS->DataSourceBuilder->WriteModules($fname,$prefix); | |
| 52 | |
| 53 if ($this->{$DBConnection}) { | |
| 54 $this->Log("Update the database '$this->{$DBConnection}[0]'"); | |
| 55 | |
| 56 $this->{$SchemaPrev} = $this->UpdateDBToSchema($schemaDB); | |
| 57 | |
| 58 } | |
| 59 $schemaDB->Dispose; | |
| 60 } | |
| 61 | |
| 62 sub Rollback { | |
| 63 my ($this) = @_; | |
| 64 | |
| 65 if ($this->{$SchemaPrev}) { | |
| 66 $this->Log("Rallback the DB schema"); | |
| 67 $this->UpdateDBToSchema($this->{$SchemaPrev})->Dispose; | |
| 68 $this->{$SchemaPrev}->Dispose; | |
| 69 delete $this->{$SchemaPrev}; | |
| 70 } | |
| 71 | |
| 72 } | |
| 73 | |
| 74 sub UpdateDBToSchema { | |
| 75 my ($this,$schemaDB) = @_; | |
| 76 my $dbh = DBI->connect(@{$this->{$DBConnection}}) or die new Exception('Failed to connect to the database',@{$this->{$DBConnection}}); | |
| 77 my $SchemaSource; | |
| 78 | |
| 79 if (UNIVERSAL::can($this->{$DBTraitsClass},'GetMetaTable')) { | |
| 80 $SchemaSource = new Deployment::CDBI::SQLSchemeSource (MetaTable => $this->{$DBTraitsClass}->GetMetaTable($dbh)); | |
| 81 } else { | |
| 82 die new Exception("Can't get a meta table",$this->{$DBTraitsClass}); | |
| 83 } | |
| 84 | |
| 85 my $schemaDBOld = $SchemaSource->ReadSchema($schemaDB->Name); | |
| 86 | |
| 87 my $updater = $this->{$DBTraitsClass}->new(SrcSchema => $schemaDBOld, DstSchema => $schemaDB); | |
| 88 $updater->UpdateSchema(); | |
| 89 | |
| 90 $dbh->do($_) or die new Exception('Failed to execute the sql statement', $_) foreach $updater->Handler->Sql; | |
| 91 | |
| 92 $SchemaSource->SaveSchema($schemaDB); | |
| 93 return $schemaDBOld; | |
| 94 } | |
| 95 | |
| 96 sub DESTROY { | |
| 97 my $this = shift; | |
| 98 | |
| 99 $this->{$SchemaPrev}->Dispose if $this->{$SchemaPrev}; | |
| 100 } | |
| 101 | |
| 102 package Deployment::CDBI::SQLSchemeSource; | |
| 103 use Common; | |
| 104 use Data::Dumper; | |
| 105 use MIME::Base64; | |
| 106 use Storable qw(nstore_fd fd_retrieve); | |
| 107 our @ISA = qw(Object); | |
| 108 | |
| 109 BEGIN { | |
| 110 DeclareProperty MetaTable => ACCESS_NONE; | |
| 111 } | |
| 112 | |
| 113 sub ReadSchema { | |
| 114 my ($this,$name) = @_; | |
| 115 | |
| 116 my $schema = decode_base64($this->{$MetaTable}->ReadProperty("db_schema_$name")); | |
| 117 if ($schema) { | |
| 118 open my $hvar,"<",\$schema or die new Exception("Failed to create a handle to the variable"); | |
| 119 return fd_retrieve($hvar); | |
| 120 } else { | |
| 121 return new Schema::DB(Name => $name, Version => 0); | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 sub SaveSchema { | |
| 126 my ($this,$schema) = @_; | |
| 127 | |
| 128 my $name = $schema->Name; | |
| 129 | |
| 130 my $data = ""; | |
| 131 { | |
| 132 open my $hvar,">",\$data or die new Exception("Failed to create a handle to the variable"); | |
| 133 nstore_fd($schema,$hvar); | |
| 134 } | |
| 135 | |
| 136 $this->{$MetaTable}->SetProperty("db_schema_$name",encode_base64($data)); | |
| 137 } | |
| 138 | |
| 139 1; |
