use Digest::SHA1 for sha1_hex
[dbsrgits/SQL-Translator-2.0-ish.git] / lib / SQL / Translator.pm
1 use MooseX::Declare;
2 class SQL::Translator {
3     use TryCatch;
4     use MooseX::Types::Moose qw(Bool HashRef Int Str Undef);
5     use SQL::Translator::Types qw(DBIHandle Parser Producer Schema);
6     use SQL::Translator::Object::Schema;
7
8     has 'parser' => (
9         isa => Str,
10         is => 'rw',
11         init_arg => 'from',
12     );
13     
14     has 'producer' => (
15         isa => Str,
16         is => 'rw',
17         init_arg => 'to',
18     );
19     
20     has '_parser' => (
21         isa => Parser,
22         is => 'rw',
23         lazy_build => 1,
24         handles => [ qw(parse) ],
25     );
26     
27     has '_producer' => (
28         isa => Producer,
29         is => 'rw',
30         lazy_build => 1,
31         handles => [ qw(produce) ],
32     );
33     
34     has 'dbh' => (
35         isa => DBIHandle,
36         is => 'ro',
37         predicate => 'has_dbh',
38     );
39
40     has 'schema' => (
41         isa => Schema,
42         is => 'rw',
43         lazy => 1,
44         default => sub { SQL::Translator::Object::Schema->new },
45     );
46
47     has 'parser_args' => (
48         isa => HashRef,
49         is => 'rw',
50         predicate => 'has_parser_args',
51     );
52
53     has 'producer_args' => (
54         isa => HashRef,
55         is => 'rw',
56         predicate => 'has_producer_args',
57     );
58     
59     has 'add_drop_table' => (isa => Bool, is => 'rw', default => 0);
60     has 'no_comments' => (isa => Bool, is => 'rw', default => 0);
61     has 'show_warnings' => (isa => Bool, is => 'rw', default => 1);
62     has 'trace' => (isa => Bool, is => 'rw', default => 0);
63     has 'quote_table_names' => (isa => Bool, is => 'rw', default => 0);
64     has 'quote_field_names' => (isa => Bool, is => 'rw', default => 0);
65     has 'version' => (isa => Str, is => 'rw');
66     has 'filename' => (isa => Str, is => 'rw');
67
68     method _build__parser {
69         my $class = 'SQL::Translator::Parser';
70     
71         Class::MOP::load_class($class);
72     
73         my $parser;
74         if ($self->has_dbh) {
75             $parser = $class->new({ translator => $self, dbh => $self->dbh });
76         } else {
77             $parser = $class->new({ translator => $self, type => $self->parser || '' });
78         }
79     
80         return $parser;
81     }
82     
83     method _build__producer {
84         my $class = 'SQL::Translator::Producer';
85         my $role = $class . '::' . $self->producer;
86
87         Class::MOP::load_class($class);
88         try {
89             Class::MOP::load_class($role)
90         } catch ($e) {
91             $role = $class . '::SQL::' . $self->producer;
92             Class::MOP::load_class($role)
93         }
94     
95         my $producer = $class->new({ translator => $self });
96         $role->meta->apply($producer);
97     
98         return $producer;
99     }
100
101     method translate(:$data, :$producer?, :$producer_args?, :$parser?, :$parser_args?) {
102         my $return;
103
104         $parser ||= $self->parser;
105         if (defined $parser) {
106             $self->_clear_parser;
107             $self->parser($parser);
108             $self->parse($data);
109             $return = $self->schema;
110         }
111
112         $producer ||= $self->producer;
113         if (defined $producer) {
114             $self->_clear_producer;
115             $self->producer($producer);
116             $return = $self->produce;
117         }
118
119         return $return;
120     }
121
122     method parser_type { return $self->parser }
123     method producer_type { return $self->producer }
124
125     method engine_version(Int|Str|Undef $v, Str $target = 'perl') {
126         return undef unless $v;
127
128         my @vers;
129
130         # X.Y.Z style 
131         if ( $v =~ / ^ (\d+) \. (\d{1,3}) (?: \. (\d{1,3}) )? $ /x ) {
132             push @vers, $1, $2, $3;
133         }
134
135         # XYYZZ (mysql) style 
136         elsif ( $v =~ / ^ (\d) (\d{2}) (\d{2}) $ /x ) {
137             push @vers, $1, $2, $3;
138         }
139
140         # XX.YYYZZZ (perl) style or simply X 
141         elsif ( $v =~ / ^ (\d+) (?: \. (\d{3}) (\d{3}) )? $ /x ) {
142             push @vers, $1, $2, $3;
143         }
144         else {
145             #how do I croak sanely here?
146             die "Unparseable MySQL version '$v'";
147         }
148
149         if ($target eq 'perl') {
150             return sprintf ('%d.%03d%03d', map { $_ || 0 } (@vers) );
151         }
152         elsif ($target eq 'mysql') {
153             return sprintf ('%d%02d%02d', map { $_ || 0 } (@vers) );
154         }
155         else {
156             #how do I croak sanely here?
157             die "Unknown version target '$target'";
158         }
159     }
160