File Coverage

blib/lib/Test/DBIx/Class/SchemaManager.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Test::DBIx::Class::SchemaManager;
2              
3 1     1   1205 use Moose;
  0            
  0            
4             use MooseX::Attribute::ENV;
5             use Moose::Util;
6             use Test::More ();
7             use List::MoreUtils qw(uniq);
8             use Test::DBIx::Class::Types qw(
9             TestBuilder SchemaManagerClass FixtureClass ConnectInfo
10             );
11              
12             has 'force_drop_table' => (
13             traits=>['ENV'],
14             is=>'rw',
15             isa=>'Bool',
16             required=>1,
17             default=>0,
18             );
19              
20             has [qw/keep_db tdbic_debug/] => (
21             traits=>['ENV'],
22             is=>'ro',
23             isa=>'Bool',
24             required=>1,
25             default=>0,
26             );
27              
28             has 'deploy_db' => (
29             traits=>['ENV'],
30             is=>'ro',
31             isa=>'Bool',
32             required=>1,
33             default=>1,
34             );
35              
36             has 'builder' => (
37             is => 'ro',
38             isa => TestBuilder,
39             required => 1,
40             );
41              
42             has 'schema_class' => (
43             traits => ['ENV'],
44             is => 'ro',
45             isa => SchemaManagerClass,
46             required => 1,
47             coerce => 1,
48             );
49              
50             has 'schema' => (
51             is => 'ro',
52             lazy_build => 1,
53             );
54              
55             has 'connect_info' => (
56             is => 'ro',
57             isa => ConnectInfo,
58             coerce => 1,
59             lazy_build => 1,
60             );
61              
62             has 'connect_opts' => (
63             is => 'ro',
64             isa => 'HashRef',
65             );
66              
67             has 'deploy_opts' => (
68             is => 'ro',
69             isa => 'HashRef',
70             default => sub { {} },
71             );
72              
73             has 'connect_info_with_opts' => (
74             is => 'ro',
75             isa => 'HashRef',
76             lazy_build => 1,
77             );
78              
79             has 'fixture_class' => (
80             traits => ['ENV'],
81             is => 'ro',
82             isa => FixtureClass,
83             required => 1,
84             coerce => 1,
85             default => '::Populate',
86             );
87              
88             has 'fixture_command' => (
89             is => 'ro',
90             init_arg => undef,
91             lazy_build => 1,
92             );
93              
94             has 'fixture_sets' => (
95             is => 'ro',
96             isa => 'HashRef',
97             );
98              
99             has 'last_statement' => (
100             is=>'rw',
101             isa=>'Str',
102             );
103              
104             sub get_fixture_sets {
105             my ($self, @sets) = @_;
106             my @return;
107             foreach my $set (@sets) {
108             if(my $fixture = $self->fixture_sets->{$set}) {
109             push @return, $fixture;
110             }
111             }
112             return @return;
113             }
114              
115             sub _build_schema {
116             my $self = shift @_;
117             my $schema_class = $self->schema_class;
118             my $connect_info = $self->connect_info_with_opts;
119              
120             return unless $schema_class;
121              
122             $schema_class = $self->prepare_schema_class($schema_class);
123              
124             return $schema_class->connect($connect_info);
125             }
126              
127             sub _build_connect_info {
128             my ($self) = @_;
129             if(my $default = $self->can('get_default_connect_info') ) {
130             return $self->$default;
131             } else {
132             Test::More::fail("Can't build a default connect info");
133             }
134             }
135              
136             sub _build_connect_info_with_opts{
137             my ($self) = @_;
138             return { %{$self->connect_info}, %{$self->connect_opts || {}} };
139             }
140              
141             sub _build_fixture_command {
142             my $self = shift @_;
143             return $self->fixture_class->new(schema_manager=>$self);
144             }
145              
146             sub prepare_schema_class {
147             my ($self, $schema_class) = @_;
148             return $schema_class;
149             }
150              
151             sub initialize_schema {
152             my ($class, $config) = @_;
153              
154             my @traits = ();
155             if(defined $config->{traits}) {
156             @traits = ref $config->{traits} ? @{$config->{traits}} : ($config->{traits});
157             }
158              
159             if(my $connect_info = $config->{connect_info}) {
160             $connect_info = to_ConnectInfo($connect_info);
161             my ($driver) = $connect_info->{dsn} =~ /dbi:([^:]+):/i;
162             if(lc $driver eq "sqlite") {
163             push @traits, 'SQLite';
164             }
165             # Don't assume mysql means we want Testmysqld; we may
166             # want to connect to a real mysql server to test.
167             } else {
168             push @traits, 'SQLite'
169             unless @traits;
170             }
171             @traits = map { __PACKAGE__."::Trait::$_"} uniq @traits;
172             $config->{traits} = \@traits;
173              
174             my $self = Moose::Util::with_traits($class, @traits)->new($config)
175             or return;
176              
177             $self->schema->storage->ensure_connected;
178             $self->setup if $self->deploy_db;
179              
180             return $self;
181             }
182              
183             ## TODO we need to fix DBIC to allow debug levels and channels
184             sub _setup_debug {
185             my $self = shift @_;
186             my $cb = $self->schema->storage->debugcb;
187              
188             $self->schema->storage->debug(1);
189             $self->schema->storage->debugcb(sub {
190             $cb->(@_) if $cb;
191             $self->last_statement($_[1]);
192             });
193             }
194              
195             sub setup {
196             my $self = shift @_;
197             my $deploy_opts = {%{$self->deploy_opts}, $self->force_drop_table ? (add_drop_table => 1) : ()};
198             if(my $schema = $self->schema) {
199             eval {
200             $schema->deploy($deploy_opts);
201             };if($@) {
202             Test::More::fail("Error Deploying Schema: $@");
203             }
204             return $self;
205             }
206             return;
207             }
208              
209             sub cleanup {
210             my $self = shift @_;
211             my $schema = $self->schema;
212              
213             return unless $schema;
214             return unless $schema->storage;
215              
216             unless ($self->keep_db) {
217             $schema->storage->with_deferred_fk_checks(sub {
218             foreach my $source ($schema->sources) {
219             my $tablesource = $schema->source($source);
220             next unless $tablesource;
221             my $table = $tablesource->name;
222             $schema->storage->dbh->do($self->drop_table_sql($table))
223             if !($schema->source($source)->can('is_virtual') &&
224             $schema->source($source)->is_virtual);
225             }
226             });
227             }
228              
229             $self->schema->storage->disconnect;
230             }
231              
232             # this has been pushed out to a method so that it can be overriden
233             # by the traits.
234             sub drop_table_sql
235             {
236             my $self = shift;
237             my $table = shift;
238             return "drop table $table";
239             }
240              
241             sub reset {
242             my $self = shift @_;
243             $self->cleanup;
244             $self->setup;
245             }
246              
247             sub install_fixtures {
248             my ($self, @args) = @_;
249             my $fixture_command = $self->fixture_command;
250             if(
251             (!ref($args[0]) && ($args[0]=~m/^::/))
252             or (ref $args[0] eq 'HASH' && $args[0]->{command}) ) {
253             my $arg = ref $args[0] ? $args[0]->{command} : $args[0];
254             my $fixture_class = to_FixtureClass($arg);
255             $self->builder->diag("Override default FixtureClass '".$self->fixture_class."' with $fixture_class") if $self->tdbic_debug;
256             $fixture_command = $fixture_class->new(schema_manager=>$self);
257             shift(@args);
258             }
259             return $self->schema->txn_do( sub {
260             $fixture_command->install_fixtures(@args);
261             });
262             }
263              
264             sub DEMOLISH {
265             my $self = shift @_;
266             if(defined $self) {
267             $self->cleanup;
268             }
269             }
270              
271             __PACKAGE__->meta->make_immutable;
272              
273             __END__