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; |